@geekity/cms 0.3.0 → 0.4.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 (637) hide show
  1. package/README.md +2091 -214
  2. package/admin/components/fields.njk +165 -0
  3. package/admin/layouts/base.njk +1 -1
  4. package/admin/layouts/settings-page.njk +26 -0
  5. package/admin/layouts/shell.njk +17 -3
  6. package/admin/pages/account/forgot.njk +47 -0
  7. package/admin/pages/account/login.njk +26 -0
  8. package/admin/pages/account/reset.njk +38 -0
  9. package/admin/pages/account/setup.njk +28 -0
  10. package/admin/pages/appearance/themes.njk +69 -0
  11. package/admin/pages/comments/all.njk +133 -0
  12. package/admin/{layouts/dashboard.njk → pages/dashboard/home.njk} +8 -15
  13. package/admin/{layouts/document-conflict.njk → pages/documents/conflict.njk} +1 -0
  14. package/admin/pages/documents/editor.njk +196 -0
  15. package/admin/{layouts/document-list.njk → pages/documents/list.njk} +19 -2
  16. package/admin/pages/documents/taxonomy.njk +95 -0
  17. package/admin/pages/federation/followers.njk +238 -0
  18. package/admin/pages/media/library.njk +160 -0
  19. package/admin/pages/messages/all.njk +110 -0
  20. package/admin/{layouts → pages}/placeholder.njk +5 -1
  21. package/admin/pages/settings/discussion.njk +99 -0
  22. package/admin/pages/settings/email.njk +203 -0
  23. package/admin/pages/settings/federation.njk +75 -0
  24. package/admin/pages/settings/general.njk +29 -0
  25. package/admin/pages/settings/permalinks.njk +50 -0
  26. package/admin/pages/settings/reading.njk +72 -0
  27. package/admin/pages/users/edit.njk +239 -0
  28. package/admin/pages/users/list.njk +48 -0
  29. package/admin/pages/users/new.njk +41 -0
  30. package/admin/static/admin.css +498 -3
  31. package/admin/static/copy.js +52 -0
  32. package/admin/static/editor.js +16 -16
  33. package/admin/static/slug.js +61 -0
  34. package/dist/admin/accounts.d.ts +413 -0
  35. package/dist/admin/accounts.d.ts.map +1 -0
  36. package/dist/admin/accounts.js +680 -0
  37. package/dist/admin/accounts.js.map +1 -0
  38. package/dist/admin/appearance.d.ts +80 -0
  39. package/dist/admin/appearance.d.ts.map +1 -0
  40. package/dist/admin/appearance.js +136 -0
  41. package/dist/admin/appearance.js.map +1 -0
  42. package/dist/admin/comments.d.ts +90 -0
  43. package/dist/admin/comments.d.ts.map +1 -0
  44. package/dist/admin/comments.js +244 -0
  45. package/dist/admin/comments.js.map +1 -0
  46. package/dist/admin/credentials.d.ts +26 -2
  47. package/dist/admin/credentials.d.ts.map +1 -1
  48. package/dist/admin/credentials.js +35 -2
  49. package/dist/admin/credentials.js.map +1 -1
  50. package/dist/admin/documents.d.ts +127 -10
  51. package/dist/admin/documents.d.ts.map +1 -1
  52. package/dist/admin/documents.js +360 -41
  53. package/dist/admin/documents.js.map +1 -1
  54. package/dist/admin/federation.d.ts +151 -50
  55. package/dist/admin/federation.d.ts.map +1 -1
  56. package/dist/admin/federation.js +225 -93
  57. package/dist/admin/federation.js.map +1 -1
  58. package/dist/admin/formatting.d.ts +20 -0
  59. package/dist/admin/formatting.d.ts.map +1 -0
  60. package/dist/admin/formatting.js +72 -0
  61. package/dist/admin/formatting.js.map +1 -0
  62. package/dist/admin/headers.d.ts +65 -0
  63. package/dist/admin/headers.d.ts.map +1 -0
  64. package/dist/admin/headers.js +104 -0
  65. package/dist/admin/headers.js.map +1 -0
  66. package/dist/admin/index.d.ts +38 -12
  67. package/dist/admin/index.d.ts.map +1 -1
  68. package/dist/admin/index.js +25 -7
  69. package/dist/admin/index.js.map +1 -1
  70. package/dist/admin/media.d.ts +168 -0
  71. package/dist/admin/media.d.ts.map +1 -0
  72. package/dist/admin/media.js +295 -0
  73. package/dist/admin/media.js.map +1 -0
  74. package/dist/admin/menu.d.ts +79 -0
  75. package/dist/admin/menu.d.ts.map +1 -0
  76. package/dist/admin/menu.js +126 -0
  77. package/dist/admin/menu.js.map +1 -0
  78. package/dist/admin/messages.d.ts +80 -0
  79. package/dist/admin/messages.d.ts.map +1 -0
  80. package/dist/admin/messages.js +152 -0
  81. package/dist/admin/messages.js.map +1 -0
  82. package/dist/admin/preview.d.ts.map +1 -1
  83. package/dist/admin/preview.js +31 -7
  84. package/dist/admin/preview.js.map +1 -1
  85. package/dist/admin/recovery.d.ts +92 -0
  86. package/dist/admin/recovery.d.ts.map +1 -0
  87. package/dist/admin/recovery.js +229 -0
  88. package/dist/admin/recovery.js.map +1 -0
  89. package/dist/admin/routes.d.ts +0 -20
  90. package/dist/admin/routes.d.ts.map +1 -1
  91. package/dist/admin/routes.js +155 -105
  92. package/dist/admin/routes.js.map +1 -1
  93. package/dist/admin/settings-discussion.d.ts +37 -0
  94. package/dist/admin/settings-discussion.d.ts.map +1 -0
  95. package/dist/admin/settings-discussion.js +117 -0
  96. package/dist/admin/settings-discussion.js.map +1 -0
  97. package/dist/admin/settings-email.d.ts +54 -0
  98. package/dist/admin/settings-email.d.ts.map +1 -0
  99. package/dist/admin/settings-email.js +189 -0
  100. package/dist/admin/settings-email.js.map +1 -0
  101. package/dist/admin/settings-federation.d.ts +39 -0
  102. package/dist/admin/settings-federation.d.ts.map +1 -0
  103. package/dist/admin/settings-federation.js +103 -0
  104. package/dist/admin/settings-federation.js.map +1 -0
  105. package/dist/admin/settings-general.d.ts +12 -0
  106. package/dist/admin/settings-general.d.ts.map +1 -0
  107. package/dist/admin/settings-general.js +48 -0
  108. package/dist/admin/settings-general.js.map +1 -0
  109. package/dist/admin/settings-page.d.ts +102 -0
  110. package/dist/admin/settings-page.d.ts.map +1 -0
  111. package/dist/admin/settings-page.js +126 -0
  112. package/dist/admin/settings-page.js.map +1 -0
  113. package/dist/admin/settings-pages.d.ts +19 -0
  114. package/dist/admin/settings-pages.d.ts.map +1 -0
  115. package/dist/admin/settings-pages.js +33 -0
  116. package/dist/admin/settings-pages.js.map +1 -0
  117. package/dist/admin/settings-permalinks.d.ts +16 -0
  118. package/dist/admin/settings-permalinks.d.ts.map +1 -0
  119. package/dist/admin/settings-permalinks.js +32 -0
  120. package/dist/admin/settings-permalinks.js.map +1 -0
  121. package/dist/admin/settings-reading.d.ts +33 -0
  122. package/dist/admin/settings-reading.d.ts.map +1 -0
  123. package/dist/admin/settings-reading.js +48 -0
  124. package/dist/admin/settings-reading.js.map +1 -0
  125. package/dist/admin/settings.d.ts +325 -96
  126. package/dist/admin/settings.d.ts.map +1 -1
  127. package/dist/admin/settings.js +650 -308
  128. package/dist/admin/settings.js.map +1 -1
  129. package/dist/admin/store.d.ts +606 -152
  130. package/dist/admin/store.d.ts.map +1 -1
  131. package/dist/admin/store.js +863 -268
  132. package/dist/admin/store.js.map +1 -1
  133. package/dist/admin/taxonomy.d.ts +114 -0
  134. package/dist/admin/taxonomy.d.ts.map +1 -0
  135. package/dist/admin/taxonomy.js +289 -0
  136. package/dist/admin/taxonomy.js.map +1 -0
  137. package/dist/admin/templates.d.ts +44 -14
  138. package/dist/admin/templates.d.ts.map +1 -1
  139. package/dist/admin/templates.js +44 -14
  140. package/dist/admin/templates.js.map +1 -1
  141. package/dist/admin/throttle.d.ts +84 -0
  142. package/dist/admin/throttle.d.ts.map +1 -0
  143. package/dist/admin/throttle.js +143 -0
  144. package/dist/admin/throttle.js.map +1 -0
  145. package/dist/admin/uploads.d.ts +28 -2
  146. package/dist/admin/uploads.d.ts.map +1 -1
  147. package/dist/admin/uploads.js +43 -4
  148. package/dist/admin/uploads.js.map +1 -1
  149. package/dist/admin/users.d.ts +100 -13
  150. package/dist/admin/users.d.ts.map +1 -1
  151. package/dist/admin/users.js +412 -39
  152. package/dist/admin/users.js.map +1 -1
  153. package/dist/cache.d.ts +141 -0
  154. package/dist/cache.d.ts.map +1 -0
  155. package/dist/cache.js +207 -0
  156. package/dist/cache.js.map +1 -0
  157. package/dist/cli.d.ts +14 -2
  158. package/dist/cli.d.ts.map +1 -1
  159. package/dist/cli.js +424 -21
  160. package/dist/cli.js.map +1 -1
  161. package/dist/comments/akismet.d.ts +130 -0
  162. package/dist/comments/akismet.d.ts.map +1 -0
  163. package/dist/comments/akismet.js +274 -0
  164. package/dist/comments/akismet.js.map +1 -0
  165. package/dist/comments/conversation.d.ts +29 -0
  166. package/dist/comments/conversation.d.ts.map +1 -0
  167. package/dist/comments/conversation.js +60 -0
  168. package/dist/comments/conversation.js.map +1 -0
  169. package/dist/comments/form.d.ts +75 -0
  170. package/dist/comments/form.d.ts.map +1 -0
  171. package/dist/comments/form.js +64 -0
  172. package/dist/comments/form.js.map +1 -0
  173. package/dist/comments/index.d.ts +15 -0
  174. package/dist/comments/index.d.ts.map +1 -0
  175. package/dist/comments/index.js +9 -0
  176. package/dist/comments/index.js.map +1 -0
  177. package/dist/comments/markdown.d.ts +8 -0
  178. package/dist/comments/markdown.d.ts.map +1 -0
  179. package/dist/comments/markdown.js +85 -0
  180. package/dist/comments/markdown.js.map +1 -0
  181. package/dist/comments/moderate.d.ts +71 -0
  182. package/dist/comments/moderate.d.ts.map +1 -0
  183. package/dist/comments/moderate.js +88 -0
  184. package/dist/comments/moderate.js.map +1 -0
  185. package/dist/comments/policy.d.ts +57 -0
  186. package/dist/comments/policy.d.ts.map +1 -0
  187. package/dist/comments/policy.js +80 -0
  188. package/dist/comments/policy.js.map +1 -0
  189. package/dist/comments/records.d.ts +266 -0
  190. package/dist/comments/records.d.ts.map +1 -0
  191. package/dist/comments/records.js +487 -0
  192. package/dist/comments/records.js.map +1 -0
  193. package/dist/comments/routes.d.ts +58 -0
  194. package/dist/comments/routes.d.ts.map +1 -0
  195. package/dist/comments/routes.js +177 -0
  196. package/dist/comments/routes.js.map +1 -0
  197. package/dist/comments/submission.d.ts +263 -0
  198. package/dist/comments/submission.d.ts.map +1 -0
  199. package/dist/comments/submission.js +241 -0
  200. package/dist/comments/submission.js.map +1 -0
  201. package/dist/config.d.ts +190 -5
  202. package/dist/config.d.ts.map +1 -1
  203. package/dist/config.js +118 -6
  204. package/dist/config.js.map +1 -1
  205. package/dist/contact/delivery.d.ts +60 -0
  206. package/dist/contact/delivery.d.ts.map +1 -0
  207. package/dist/contact/delivery.js +87 -0
  208. package/dist/contact/delivery.js.map +1 -0
  209. package/dist/contact/form.d.ts +130 -0
  210. package/dist/contact/form.d.ts.map +1 -0
  211. package/dist/contact/form.js +163 -0
  212. package/dist/contact/form.js.map +1 -0
  213. package/dist/contact/index.d.ts +17 -0
  214. package/dist/contact/index.d.ts.map +1 -0
  215. package/dist/contact/index.js +13 -0
  216. package/dist/contact/index.js.map +1 -0
  217. package/dist/contact/records.d.ts +124 -0
  218. package/dist/contact/records.d.ts.map +1 -0
  219. package/dist/contact/records.js +218 -0
  220. package/dist/contact/records.js.map +1 -0
  221. package/dist/contact/routes.d.ts +17 -0
  222. package/dist/contact/routes.d.ts.map +1 -0
  223. package/dist/contact/routes.js +127 -0
  224. package/dist/contact/routes.js.map +1 -0
  225. package/dist/contact/submission.d.ts +103 -0
  226. package/dist/contact/submission.d.ts.map +1 -0
  227. package/dist/contact/submission.js +166 -0
  228. package/dist/contact/submission.js.map +1 -0
  229. package/dist/content/document.d.ts +7 -2
  230. package/dist/content/document.d.ts.map +1 -1
  231. package/dist/content/document.js +1 -0
  232. package/dist/content/document.js.map +1 -1
  233. package/dist/content/index.d.ts +7 -2
  234. package/dist/content/index.d.ts.map +1 -1
  235. package/dist/content/index.js +4 -1
  236. package/dist/content/index.js.map +1 -1
  237. package/dist/content/markdown.d.ts.map +1 -1
  238. package/dist/content/markdown.js +24 -2
  239. package/dist/content/markdown.js.map +1 -1
  240. package/dist/content/parser.d.ts.map +1 -1
  241. package/dist/content/parser.js +11 -4
  242. package/dist/content/parser.js.map +1 -1
  243. package/dist/content/save.d.ts +5 -0
  244. package/dist/content/save.d.ts.map +1 -1
  245. package/dist/content/save.js +44 -1
  246. package/dist/content/save.js.map +1 -1
  247. package/dist/content/schedule.d.ts +125 -0
  248. package/dist/content/schedule.d.ts.map +1 -0
  249. package/dist/content/schedule.js +207 -0
  250. package/dist/content/schedule.js.map +1 -0
  251. package/dist/content/search.d.ts +64 -0
  252. package/dist/content/search.d.ts.map +1 -0
  253. package/dist/content/search.js +136 -0
  254. package/dist/content/search.js.map +1 -0
  255. package/dist/content/store.d.ts +202 -7
  256. package/dist/content/store.d.ts.map +1 -1
  257. package/dist/content/store.js +374 -67
  258. package/dist/content/store.js.map +1 -1
  259. package/dist/content/sync.d.ts +7 -1
  260. package/dist/content/sync.d.ts.map +1 -1
  261. package/dist/content/sync.js +18 -10
  262. package/dist/content/sync.js.map +1 -1
  263. package/dist/content/time.d.ts +56 -0
  264. package/dist/content/time.d.ts.map +1 -0
  265. package/dist/content/time.js +141 -0
  266. package/dist/content/time.js.map +1 -0
  267. package/dist/content/writer.d.ts.map +1 -1
  268. package/dist/content/writer.js +3 -0
  269. package/dist/content/writer.js.map +1 -1
  270. package/dist/env.d.ts +58 -4
  271. package/dist/env.d.ts.map +1 -1
  272. package/dist/federation/actor.d.ts +95 -41
  273. package/dist/federation/actor.d.ts.map +1 -1
  274. package/dist/federation/actor.js +180 -53
  275. package/dist/federation/actor.js.map +1 -1
  276. package/dist/federation/article.d.ts +44 -17
  277. package/dist/federation/article.d.ts.map +1 -1
  278. package/dist/federation/article.js +98 -46
  279. package/dist/federation/article.js.map +1 -1
  280. package/dist/federation/delivery.d.ts +63 -15
  281. package/dist/federation/delivery.d.ts.map +1 -1
  282. package/dist/federation/delivery.js +154 -80
  283. package/dist/federation/delivery.js.map +1 -1
  284. package/dist/federation/federation.d.ts +22 -17
  285. package/dist/federation/federation.d.ts.map +1 -1
  286. package/dist/federation/federation.js +98 -77
  287. package/dist/federation/federation.js.map +1 -1
  288. package/dist/federation/followers.d.ts +3 -2
  289. package/dist/federation/followers.d.ts.map +1 -1
  290. package/dist/federation/followers.js +6 -5
  291. package/dist/federation/followers.js.map +1 -1
  292. package/dist/federation/import-wordpress.d.ts +128 -0
  293. package/dist/federation/import-wordpress.d.ts.map +1 -0
  294. package/dist/federation/import-wordpress.js +426 -0
  295. package/dist/federation/import-wordpress.js.map +1 -0
  296. package/dist/federation/inbox.d.ts +36 -13
  297. package/dist/federation/inbox.d.ts.map +1 -1
  298. package/dist/federation/inbox.js +120 -49
  299. package/dist/federation/inbox.js.map +1 -1
  300. package/dist/federation/index.d.ts +22 -10
  301. package/dist/federation/index.d.ts.map +1 -1
  302. package/dist/federation/index.js +13 -8
  303. package/dist/federation/index.js.map +1 -1
  304. package/dist/federation/keys.d.ts +98 -20
  305. package/dist/federation/keys.d.ts.map +1 -1
  306. package/dist/federation/keys.js +269 -39
  307. package/dist/federation/keys.js.map +1 -1
  308. package/dist/federation/mount.d.ts +42 -10
  309. package/dist/federation/mount.d.ts.map +1 -1
  310. package/dist/federation/mount.js +266 -26
  311. package/dist/federation/mount.js.map +1 -1
  312. package/dist/federation/paths.d.ts +23 -35
  313. package/dist/federation/paths.d.ts.map +1 -1
  314. package/dist/federation/paths.js +26 -39
  315. package/dist/federation/paths.js.map +1 -1
  316. package/dist/federation/records.d.ts +223 -0
  317. package/dist/federation/records.d.ts.map +1 -0
  318. package/dist/federation/records.js +506 -0
  319. package/dist/federation/records.js.map +1 -0
  320. package/dist/federation/relays.d.ts +114 -0
  321. package/dist/federation/relays.d.ts.map +1 -0
  322. package/dist/federation/relays.js +290 -0
  323. package/dist/federation/relays.js.map +1 -0
  324. package/dist/federation/replies.d.ts +80 -0
  325. package/dist/federation/replies.d.ts.map +1 -0
  326. package/dist/federation/replies.js +166 -0
  327. package/dist/federation/replies.js.map +1 -0
  328. package/dist/federation/wordpress.d.ts +131 -0
  329. package/dist/federation/wordpress.d.ts.map +1 -0
  330. package/dist/federation/wordpress.js +341 -0
  331. package/dist/federation/wordpress.js.map +1 -0
  332. package/dist/files/atomic.d.ts +103 -0
  333. package/dist/files/atomic.d.ts.map +1 -0
  334. package/dist/files/atomic.js +150 -0
  335. package/dist/files/atomic.js.map +1 -0
  336. package/dist/files/index.d.ts +3 -0
  337. package/dist/files/index.d.ts.map +1 -0
  338. package/dist/files/index.js +2 -0
  339. package/dist/files/index.js.map +1 -0
  340. package/dist/forms/protection.d.ts +85 -0
  341. package/dist/forms/protection.d.ts.map +1 -0
  342. package/dist/forms/protection.js +116 -0
  343. package/dist/forms/protection.js.map +1 -0
  344. package/dist/images/icons.d.ts +59 -0
  345. package/dist/images/icons.d.ts.map +1 -0
  346. package/dist/images/icons.js +131 -0
  347. package/dist/images/icons.js.map +1 -0
  348. package/dist/images/index.d.ts +7 -0
  349. package/dist/images/index.d.ts.map +1 -0
  350. package/dist/images/index.js +4 -0
  351. package/dist/images/index.js.map +1 -0
  352. package/dist/images/markup.d.ts +47 -0
  353. package/dist/images/markup.d.ts.map +1 -0
  354. package/dist/images/markup.js +175 -0
  355. package/dist/images/markup.js.map +1 -0
  356. package/dist/images/paths.d.ts +34 -0
  357. package/dist/images/paths.d.ts.map +1 -0
  358. package/dist/images/paths.js +41 -0
  359. package/dist/images/paths.js.map +1 -0
  360. package/dist/images/variants.d.ts +104 -0
  361. package/dist/images/variants.d.ts.map +1 -0
  362. package/dist/images/variants.js +320 -0
  363. package/dist/images/variants.js.map +1 -0
  364. package/dist/index.d.ts +123 -19
  365. package/dist/index.d.ts.map +1 -1
  366. package/dist/index.js +327 -25
  367. package/dist/index.js.map +1 -1
  368. package/dist/init.d.ts +18 -0
  369. package/dist/init.d.ts.map +1 -1
  370. package/dist/init.js +34 -3
  371. package/dist/init.js.map +1 -1
  372. package/dist/mail/brevo.d.ts +35 -0
  373. package/dist/mail/brevo.d.ts.map +1 -0
  374. package/dist/mail/brevo.js +85 -0
  375. package/dist/mail/brevo.js.map +1 -0
  376. package/dist/mail/credentials.d.ts +62 -0
  377. package/dist/mail/credentials.d.ts.map +1 -0
  378. package/dist/mail/credentials.js +86 -0
  379. package/dist/mail/credentials.js.map +1 -0
  380. package/dist/mail/index.d.ts +15 -0
  381. package/dist/mail/index.d.ts.map +1 -0
  382. package/dist/mail/index.js +8 -0
  383. package/dist/mail/index.js.map +1 -0
  384. package/dist/mail/memory.d.ts +35 -0
  385. package/dist/mail/memory.d.ts.map +1 -0
  386. package/dist/mail/memory.js +29 -0
  387. package/dist/mail/memory.js.map +1 -0
  388. package/dist/mail/provider.d.ts +80 -0
  389. package/dist/mail/provider.d.ts.map +1 -0
  390. package/dist/mail/provider.js +23 -0
  391. package/dist/mail/provider.js.map +1 -0
  392. package/dist/mail/service.d.ts +156 -0
  393. package/dist/mail/service.d.ts.map +1 -0
  394. package/dist/mail/service.js +265 -0
  395. package/dist/mail/service.js.map +1 -0
  396. package/dist/mail/smtp.d.ts +39 -0
  397. package/dist/mail/smtp.d.ts.map +1 -0
  398. package/dist/mail/smtp.js +58 -0
  399. package/dist/mail/smtp.js.map +1 -0
  400. package/dist/mail/templates.d.ts +91 -0
  401. package/dist/mail/templates.d.ts.map +1 -0
  402. package/dist/mail/templates.js +69 -0
  403. package/dist/mail/templates.js.map +1 -0
  404. package/dist/notifications/comments.d.ts +66 -0
  405. package/dist/notifications/comments.d.ts.map +1 -0
  406. package/dist/notifications/comments.js +151 -0
  407. package/dist/notifications/comments.js.map +1 -0
  408. package/dist/notifications/digest.d.ts +135 -0
  409. package/dist/notifications/digest.d.ts.map +1 -0
  410. package/dist/notifications/digest.js +287 -0
  411. package/dist/notifications/digest.js.map +1 -0
  412. package/dist/notifications/index.d.ts +13 -0
  413. package/dist/notifications/index.d.ts.map +1 -0
  414. package/dist/notifications/index.js +8 -0
  415. package/dist/notifications/index.js.map +1 -0
  416. package/dist/notifications/links.d.ts +60 -0
  417. package/dist/notifications/links.d.ts.map +1 -0
  418. package/dist/notifications/links.js +63 -0
  419. package/dist/notifications/links.js.map +1 -0
  420. package/dist/notifications/optouts.d.ts +48 -0
  421. package/dist/notifications/optouts.d.ts.map +1 -0
  422. package/dist/notifications/optouts.js +93 -0
  423. package/dist/notifications/optouts.js.map +1 -0
  424. package/dist/notifications/preferences.d.ts +158 -0
  425. package/dist/notifications/preferences.d.ts.map +1 -0
  426. package/dist/notifications/preferences.js +195 -0
  427. package/dist/notifications/preferences.js.map +1 -0
  428. package/dist/notifications/routes.d.ts +28 -0
  429. package/dist/notifications/routes.d.ts.map +1 -0
  430. package/dist/notifications/routes.js +184 -0
  431. package/dist/notifications/routes.js.map +1 -0
  432. package/dist/notifications/tokens.d.ts +60 -0
  433. package/dist/notifications/tokens.d.ts.map +1 -0
  434. package/dist/notifications/tokens.js +125 -0
  435. package/dist/notifications/tokens.js.map +1 -0
  436. package/dist/notify.d.ts +84 -0
  437. package/dist/notify.d.ts.map +1 -0
  438. package/dist/notify.js +149 -0
  439. package/dist/notify.js.map +1 -0
  440. package/dist/web/archive.d.ts +49 -0
  441. package/dist/web/archive.d.ts.map +1 -0
  442. package/dist/web/archive.js +59 -0
  443. package/dist/web/archive.js.map +1 -0
  444. package/dist/web/assets.d.ts +6 -5
  445. package/dist/web/assets.d.ts.map +1 -1
  446. package/dist/web/assets.js +5 -7
  447. package/dist/web/assets.js.map +1 -1
  448. package/dist/web/authors.d.ts +143 -0
  449. package/dist/web/authors.d.ts.map +1 -0
  450. package/dist/web/authors.js +178 -0
  451. package/dist/web/authors.js.map +1 -0
  452. package/dist/web/comments.d.ts +60 -0
  453. package/dist/web/comments.d.ts.map +1 -0
  454. package/dist/web/comments.js +207 -0
  455. package/dist/web/comments.js.map +1 -0
  456. package/dist/web/context.d.ts +162 -28
  457. package/dist/web/context.d.ts.map +1 -1
  458. package/dist/web/context.js +123 -26
  459. package/dist/web/context.js.map +1 -1
  460. package/dist/web/conversation.d.ts +209 -0
  461. package/dist/web/conversation.d.ts.map +1 -0
  462. package/dist/web/conversation.js +557 -0
  463. package/dist/web/conversation.js.map +1 -0
  464. package/dist/web/documents.d.ts +36 -6
  465. package/dist/web/documents.d.ts.map +1 -1
  466. package/dist/web/documents.js +52 -10
  467. package/dist/web/documents.js.map +1 -1
  468. package/dist/web/feed-atom.d.ts +22 -0
  469. package/dist/web/feed-atom.d.ts.map +1 -0
  470. package/dist/web/feed-atom.js +83 -0
  471. package/dist/web/feed-atom.js.map +1 -0
  472. package/dist/web/feed-item.d.ts +145 -0
  473. package/dist/web/feed-item.d.ts.map +1 -0
  474. package/dist/web/feed-item.js +120 -0
  475. package/dist/web/feed-item.js.map +1 -0
  476. package/dist/web/feed-json.d.ts +79 -0
  477. package/dist/web/feed-json.d.ts.map +1 -0
  478. package/dist/web/feed-json.js +53 -0
  479. package/dist/web/feed-json.js.map +1 -0
  480. package/dist/web/feed-rss.d.ts +26 -0
  481. package/dist/web/feed-rss.d.ts.map +1 -0
  482. package/dist/web/feed-rss.js +203 -0
  483. package/dist/web/feed-rss.js.map +1 -0
  484. package/dist/web/feed-source.d.ts +244 -0
  485. package/dist/web/feed-source.d.ts.map +1 -0
  486. package/dist/web/feed-source.js +201 -0
  487. package/dist/web/feed-source.js.map +1 -0
  488. package/dist/web/feed-xml.d.ts +63 -0
  489. package/dist/web/feed-xml.d.ts.map +1 -0
  490. package/dist/web/feed-xml.js +116 -0
  491. package/dist/web/feed-xml.js.map +1 -0
  492. package/dist/web/feeds.d.ts +31 -96
  493. package/dist/web/feeds.d.ts.map +1 -1
  494. package/dist/web/feeds.js +94 -198
  495. package/dist/web/feeds.js.map +1 -1
  496. package/dist/web/health.d.ts +31 -0
  497. package/dist/web/health.d.ts.map +1 -0
  498. package/dist/web/health.js +44 -0
  499. package/dist/web/health.js.map +1 -0
  500. package/dist/web/index.d.ts +30 -10
  501. package/dist/web/index.d.ts.map +1 -1
  502. package/dist/web/index.js +18 -7
  503. package/dist/web/index.js.map +1 -1
  504. package/dist/web/navigation.d.ts +73 -0
  505. package/dist/web/navigation.d.ts.map +1 -0
  506. package/dist/web/navigation.js +110 -0
  507. package/dist/web/navigation.js.map +1 -0
  508. package/dist/web/negotiate.d.ts +9 -0
  509. package/dist/web/negotiate.d.ts.map +1 -1
  510. package/dist/web/negotiate.js +6 -1
  511. package/dist/web/negotiate.js.map +1 -1
  512. package/dist/web/recent.d.ts +43 -0
  513. package/dist/web/recent.d.ts.map +1 -0
  514. package/dist/web/recent.js +37 -0
  515. package/dist/web/recent.js.map +1 -0
  516. package/dist/web/render.d.ts +197 -9
  517. package/dist/web/render.d.ts.map +1 -1
  518. package/dist/web/render.js +334 -17
  519. package/dist/web/render.js.map +1 -1
  520. package/dist/web/routes.d.ts +25 -8
  521. package/dist/web/routes.d.ts.map +1 -1
  522. package/dist/web/routes.js +845 -93
  523. package/dist/web/routes.js.map +1 -1
  524. package/dist/web/sanitize.d.ts +19 -0
  525. package/dist/web/sanitize.d.ts.map +1 -0
  526. package/dist/web/sanitize.js +272 -0
  527. package/dist/web/sanitize.js.map +1 -0
  528. package/dist/web/search.d.ts +79 -0
  529. package/dist/web/search.d.ts.map +1 -0
  530. package/dist/web/search.js +94 -0
  531. package/dist/web/search.js.map +1 -0
  532. package/dist/web/sitemap.d.ts +120 -0
  533. package/dist/web/sitemap.d.ts.map +1 -0
  534. package/dist/web/sitemap.js +199 -0
  535. package/dist/web/sitemap.js.map +1 -0
  536. package/dist/web/taxonomy.d.ts +152 -0
  537. package/dist/web/taxonomy.d.ts.map +1 -0
  538. package/dist/web/taxonomy.js +237 -0
  539. package/dist/web/taxonomy.js.map +1 -0
  540. package/dist/web/templates.d.ts +54 -16
  541. package/dist/web/templates.d.ts.map +1 -1
  542. package/dist/web/templates.js +109 -28
  543. package/dist/web/templates.js.map +1 -1
  544. package/dist/web/themes.d.ts +205 -0
  545. package/dist/web/themes.d.ts.map +1 -0
  546. package/dist/web/themes.js +277 -0
  547. package/dist/web/themes.js.map +1 -0
  548. package/dist/webmention/discovery.d.ts +51 -0
  549. package/dist/webmention/discovery.d.ts.map +1 -0
  550. package/dist/webmention/discovery.js +176 -0
  551. package/dist/webmention/discovery.js.map +1 -0
  552. package/dist/webmention/html.d.ts +71 -0
  553. package/dist/webmention/html.d.ts.map +1 -0
  554. package/dist/webmention/html.js +285 -0
  555. package/dist/webmention/html.js.map +1 -0
  556. package/dist/webmention/index.d.ts +12 -0
  557. package/dist/webmention/index.d.ts.map +1 -0
  558. package/dist/webmention/index.js +8 -0
  559. package/dist/webmention/index.js.map +1 -0
  560. package/dist/webmention/links.d.ts +18 -0
  561. package/dist/webmention/links.d.ts.map +1 -0
  562. package/dist/webmention/links.js +64 -0
  563. package/dist/webmention/links.js.map +1 -0
  564. package/dist/webmention/microformats.d.ts +93 -0
  565. package/dist/webmention/microformats.d.ts.map +1 -0
  566. package/dist/webmention/microformats.js +376 -0
  567. package/dist/webmention/microformats.js.map +1 -0
  568. package/dist/webmention/receive.d.ts +141 -0
  569. package/dist/webmention/receive.d.ts.map +1 -0
  570. package/dist/webmention/receive.js +264 -0
  571. package/dist/webmention/receive.js.map +1 -0
  572. package/dist/webmention/routes.d.ts +37 -0
  573. package/dist/webmention/routes.d.ts.map +1 -0
  574. package/dist/webmention/routes.js +75 -0
  575. package/dist/webmention/routes.js.map +1 -0
  576. package/dist/webmention/service.d.ts +94 -0
  577. package/dist/webmention/service.d.ts.map +1 -0
  578. package/dist/webmention/service.js +207 -0
  579. package/dist/webmention/service.js.map +1 -0
  580. package/package.json +11 -6
  581. package/templates/site/content/_data/site.json +1 -0
  582. package/templates/site/content/posts/2026-01-01-hello-world.md +5 -3
  583. package/templates/site/geekity.config.ts +11 -1
  584. package/templates/site/tsconfig.json +1 -1
  585. package/themes/default/README.md +1096 -50
  586. package/themes/default/layouts/404.njk +2 -3
  587. package/themes/default/layouts/author.njk +37 -0
  588. package/themes/default/layouts/base.njk +172 -31
  589. package/themes/default/layouts/category.njk +27 -0
  590. package/themes/default/layouts/front-page.njk +57 -0
  591. package/themes/default/layouts/home.njk +17 -1
  592. package/themes/default/layouts/page.njk +57 -5
  593. package/themes/default/layouts/post.njk +78 -19
  594. package/themes/default/layouts/search.njk +57 -0
  595. package/themes/default/layouts/tag.njk +3 -6
  596. package/themes/default/mail/comment-digest.html.njk +37 -0
  597. package/themes/default/mail/comment-digest.subject.njk +3 -0
  598. package/themes/default/mail/comment-digest.txt.njk +40 -0
  599. package/themes/default/mail/comment-pending.html.njk +27 -0
  600. package/themes/default/mail/comment-pending.subject.njk +2 -0
  601. package/themes/default/mail/comment-pending.txt.njk +24 -0
  602. package/themes/default/mail/comment-reply.html.njk +21 -0
  603. package/themes/default/mail/comment-reply.subject.njk +2 -0
  604. package/themes/default/mail/comment-reply.txt.njk +22 -0
  605. package/themes/default/mail/contact-message.html.njk +24 -0
  606. package/themes/default/mail/contact-message.subject.njk +5 -0
  607. package/themes/default/mail/contact-message.txt.njk +20 -0
  608. package/themes/default/mail/password-changed.html.njk +18 -0
  609. package/themes/default/mail/password-changed.subject.njk +2 -0
  610. package/themes/default/mail/password-changed.txt.njk +17 -0
  611. package/themes/default/mail/password-reset.html.njk +22 -0
  612. package/themes/default/mail/password-reset.subject.njk +2 -0
  613. package/themes/default/mail/password-reset.txt.njk +18 -0
  614. package/themes/default/mail/test.html.njk +14 -0
  615. package/themes/default/mail/test.subject.njk +2 -0
  616. package/themes/default/mail/test.txt.njk +12 -0
  617. package/themes/default/partials/archive.njk +27 -0
  618. package/themes/default/partials/bio.njk +77 -0
  619. package/themes/default/partials/comment-form.njk +109 -0
  620. package/themes/default/partials/contact-form.njk +88 -0
  621. package/themes/default/partials/conversation.njk +139 -0
  622. package/themes/default/partials/feeds.njk +26 -0
  623. package/themes/default/partials/jsonld.njk +120 -0
  624. package/themes/default/partials/pagination.njk +12 -6
  625. package/themes/default/partials/post-list.njk +51 -18
  626. package/themes/default/partials/search-form.njk +17 -0
  627. package/themes/default/partials/tags.njk +26 -5
  628. package/themes/default/static/highlight.js +4 -0
  629. package/themes/default/static/style.css +1119 -194
  630. package/themes/default/theme.json +5 -0
  631. package/admin/layouts/document-editor.njk +0 -167
  632. package/admin/layouts/federation.njk +0 -145
  633. package/admin/layouts/login.njk +0 -23
  634. package/admin/layouts/settings.njk +0 -116
  635. package/admin/layouts/setup.njk +0 -27
  636. package/admin/layouts/users.njk +0 -91
  637. /package/admin/{layouts/_flash.njk → components/flash.njk} +0 -0
@@ -0,0 +1,29 @@
1
+ {# /admin/settings: what the site is called, where it lives, and its picture. #}
2
+ {% extends "layouts/settings-page.njk" %}
3
+ {% import "components/fields.njk" as field %}
4
+
5
+ {% block settingsFields %}
6
+ {{ field.text('settings-title', fields.title, 'Title', form.title,
7
+ error=problems.title, required=true, autofocus=true) }}
8
+
9
+ {{ field.text('settings-tagline', fields.tagline, 'Tagline', form.tagline,
10
+ hint='One line, shown under the title and used as the feed subtitle.') }}
11
+
12
+ {{ field.text('settings-author', fields.author, 'Author', form.author,
13
+ hint='The name on the feeds.') }}
14
+
15
+ {% set baseUrlHint %}In effect: <code>{{ baseUrlInEffect }}</code>. {{ baseUrlNote }}{% endset %}
16
+ {{ field.text('settings-base-url', fields.baseUrl, 'Base URL', form.baseUrl,
17
+ error=problems.baseUrl, hint=baseUrlHint, inputmode='url',
18
+ readonly=baseUrlOverridden, disabled=baseUrlOverridden) }}
19
+
20
+ {% set timezoneHint %}An IANA name, such as <code>Europe/London</code> or <code>UTC</code>.{% endset %}
21
+ {{ field.text('settings-timezone', fields.timezone, 'Time zone', form.timezone,
22
+ error=problems.timezone, hint=timezoneHint, required=true) }}
23
+
24
+ {% set languageHint %}A BCP 47 tag, such as <code>en</code> or <code>en-GB</code>. It is the page's <code>lang</code> and the feeds' language.{% endset %}
25
+ {{ field.text('settings-language', fields.language, 'Language', form.language,
26
+ error=problems.language, hint=languageHint, required=true) }}
27
+ {% endblock %}
28
+
29
+ {% block settingsPanels %}{% endblock %}
@@ -0,0 +1,50 @@
1
+ {# /admin/settings/permalinks: the URLs the archives live at, and the ones they
2
+ used to. #}
3
+ {% extends "layouts/settings-page.njk" %}
4
+ {% import "components/fields.njk" as field %}
5
+
6
+ {% block settingsFields %}
7
+ {% set tagBaseHint %}The tag archives live at <code>/{{ form.tagBase }}/{tag}/</code>. One path segment, no slashes.{% endset %}
8
+ {{ field.text('settings-tag-base', fields.tagBase, 'Tag base', form.tagBase,
9
+ error=problems.tagBase, hint=tagBaseHint, required=true, autofocus=true) }}
10
+
11
+ {% set categoryBaseHint %}The category archives live at <code>/{{ form.categoryBase }}/{name}/</code>.{% endset %}
12
+ {{ field.text('settings-category-base', fields.categoryBase, 'Category base', form.categoryBase,
13
+ error=problems.categoryBase, hint=categoryBaseHint, required=true) }}
14
+ {% endblock %}
15
+
16
+ {% block settingsPanels %}
17
+ {# The recorded renames are a record of what happened rather than a
18
+ preference: the taxonomy screens write them as a term is renamed or merged,
19
+ and this page is where the URLs they are about are decided. #}
20
+ <section class="admin-settings admin-redirects-panel">
21
+ <h2>Archive redirects</h2>
22
+
23
+ {% if taxonomyRedirects.length %}
24
+ <table class="admin-list">
25
+ <thead>
26
+ <tr><th scope="col">Taxonomy</th><th scope="col">Was</th><th scope="col">Is now</th></tr>
27
+ </thead>
28
+ <tbody>
29
+ {% for redirect in taxonomyRedirects %}
30
+ <tr>
31
+ <td>{{ redirect.label }}</td>
32
+ <td><code>{{ redirect.from }}</code></td>
33
+ <td><code>{{ redirect.to }}</code></td>
34
+ </tr>
35
+ {% endfor %}
36
+ </tbody>
37
+ </table>
38
+ <p class="admin-hint">
39
+ Every one of these answers with a permanent redirect to the archive the
40
+ term lives at now, so a link somebody published still arrives.
41
+ </p>
42
+ {% else %}
43
+ <p class="admin-hint">
44
+ Nothing has moved yet. Renaming or merging a term on the Tags or
45
+ Categories screen records the archive URL it used to have here, and the
46
+ site answers that URL with a permanent redirect from then on.
47
+ </p>
48
+ {% endif %}
49
+ </section>
50
+ {% endblock %}
@@ -0,0 +1,72 @@
1
+ {# /admin/settings/reading: what a visitor is shown, and who is told when it
2
+ changes. #}
3
+ {% extends "layouts/settings-page.njk" %}
4
+ {% import "components/fields.njk" as field %}
5
+
6
+ {% block settingsFields %}
7
+ {# WordPress's "Your homepage displays": the empty option is Your latest
8
+ posts, so the choice and the page it needs are one control rather than a
9
+ radio and a select that can disagree with each other. #}
10
+ {% set homepageGone %}
11
+ {% if homepageMissing %}
12
+ <p class="admin-field-error">
13
+ The homepage was <code>{{ form.homepage }}</code>, which is no longer published,
14
+ so the site is showing its latest posts. Publish that page again to have it back,
15
+ or pick another.
16
+ </p>
17
+ {% endif %}
18
+ {% endset %}
19
+ {% set homepageHint %}
20
+ Your latest posts is the archive at <code>/</code>. A page instead is served
21
+ there, and its own URL redirects to <code>/</code> so there is one front page.
22
+ {% endset %}
23
+ {% call field.select('settings-homepage', fields.homepage, 'Your homepage displays',
24
+ error=problems.homepage, errorHtml=homepageGone, hint=homepageHint, autofocus=true) %}
25
+ <option value="">Your latest posts</option>
26
+ {% for page in pageChoices %}
27
+ <option value="{{ page.slug }}"{% if page.slug == form.homepage %} selected{% endif %}>{{ page.title }}</option>
28
+ {% endfor %}
29
+ {% endcall %}
30
+
31
+ {% set postsPageGone %}
32
+ {% if postsPageMissing %}
33
+ <p class="admin-field-error">
34
+ The posts page was <code>{{ form.postsPage }}</code>, which is no longer published,
35
+ so the listing has no page of its own.
36
+ </p>
37
+ {% endif %}
38
+ {% endset %}
39
+ {% set postsPageHint %}
40
+ Where the posts go once the homepage is a page: this page's URL carries the
41
+ listing, with its own title and words above it. It needs a homepage first.
42
+ The feeds stay at <code>/feed/</code> either way.
43
+ {% endset %}
44
+ {% call field.select('settings-posts-page', fields.postsPage, 'Posts page',
45
+ error=problems.postsPage, errorHtml=postsPageGone, hint=postsPageHint) %}
46
+ <option value="">&mdash; None &mdash;</option>
47
+ {% for page in pageChoices %}
48
+ <option value="{{ page.slug }}"{% if page.slug == form.postsPage %} selected{% endif %}>{{ page.title }}</option>
49
+ {% endfor %}
50
+ {% endcall %}
51
+
52
+ {{ field.text('settings-posts-per-page', fields.postsPerPage, 'Posts per page', form.postsPerPage,
53
+ error=problems.postsPerPage, inputmode='numeric', required=true,
54
+ hint='How many posts a listing page holds, on the home page and on every archive.') }}
55
+
56
+ {% set navigationHint %}
57
+ One item per line, written <code>Label | URL</code> &mdash; for example
58
+ <code>About | /about/</code> or <code>Mastodon | https://example.social/@me</code>.
59
+ They are the menu in the site header, in this order. A page can put itself
60
+ on the end of it by ticking <em>Show in navigation</em> in the editor.
61
+ {% endset %}
62
+ {{ field.textarea('settings-navigation', fields.navigation, 'Menu', form.navigation,
63
+ error=problems.navigation, hint=navigationHint, rows='4', spellcheck='false') }}
64
+
65
+ {% set notifyHint %}
66
+ An rssCloud and WebSub server, told whenever a feed changes so subscribers
67
+ hear at once instead of waiting for their next poll. Every feed advertises
68
+ it. Leave it empty for none.
69
+ {% endset %}
70
+ {{ field.text('settings-notify-server', fields.notifyServer, 'Notify server', form.notifyServer,
71
+ error=problems.notifyServer, hint=notifyHint, inputmode='url') }}
72
+ {% endblock %}
@@ -0,0 +1,239 @@
1
+ {# /admin/users/<id>: everything about one person, a panel at a time.
2
+
3
+ The table behind it says who there is; this says what they are. Every box
4
+ here carries a label the eye can read, because these fields used to sit in
5
+ a row of that table where a placeholder was the only thing telling them
6
+ apart — and a placeholder disappears the moment somebody types.
7
+
8
+ Four forms rather than one, for the reason there were four before: an email
9
+ address is private to the site and a profile is the public face, a notice
10
+ switch is a button and how often it arrives is a select, and a password is
11
+ about whoever is signed in. Each saves what its own heading is about and
12
+ lands back here, so a Save always shows its own result. #}
13
+ {% extends "layouts/shell.njk" %}
14
+ {% import "components/fields.njk" as field %}
15
+
16
+ {% block title %}Edit {{ account.username }}{% endblock %}
17
+
18
+ {% block content %}
19
+ <h1>Edit {{ account.username }}{% if account.you %} <span class="admin-status">(you)</span>{% endif %}</h1>
20
+
21
+ <p class="admin-hint"><a href="{{ usersUrl }}">Back to all users</a></p>
22
+
23
+ <form class="admin-settings" method="post" action="{{ userEmailUrl }}">
24
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
25
+ <input type="hidden" name="{{ fields.userId }}" value="{{ account.id }}" />
26
+
27
+ <h2>Account</h2>
28
+
29
+ <p class="admin-field-static">
30
+ Signs in as <strong>{{ account.username }}</strong>, and writes at
31
+ <a href="{{ account.archiveUrl }}">{{ account.archiveUrl }}</a>.
32
+ </p>
33
+ <p class="admin-hint">
34
+ A username is not editable: it is the login, the author URL above, and
35
+ the actor a follower holds. Somebody who needs a different one is a new
36
+ account.
37
+ </p>
38
+ {# The id they were published under somewhere else (TASK-69). Read-only on
39
+ purpose: it is what the fediverse already holds, and changing it would
40
+ orphan every follow. #}
41
+ {% if account.storedActorId %}
42
+ <p class="admin-hint">
43
+ Also <code>{{ account.storedActorId }}</code> — what the fediverse knows
44
+ this user by. Set by the import or by hand in
45
+ <code>data/users.json</code>, never here.
46
+ </p>
47
+ {% endif %}
48
+
49
+ {% set emailHint %}
50
+ {% if mailConfigured %}
51
+ Optional, and never shown on the public site. It is what a forgotten password is recovered through and where the notices below go. Empty it to stop the site writing to this person at all.
52
+ {% else %}
53
+ Optional, and this site sends no mail yet, so nothing will be sent to one. Choose a provider on <a href="{{ adminUrl }}/settings/email">Settings &rsaquo; Email</a> to turn password recovery on.
54
+ {% endif %}
55
+ {% endset %}
56
+ {{ field.text('user-email', fields.email, 'Email address', account.email,
57
+ type='email', autocomplete='email', hint=emailHint) }}
58
+
59
+ <p class="admin-settings-buttons">
60
+ <button type="submit">Save email address</button>
61
+ </p>
62
+ </form>
63
+
64
+ {# The public face of this person (TASK-67). Anybody's, not only your own:
65
+ there is one role, so an admin who has just added a colleague can put a
66
+ name and a line about them on their archive without waiting for them to
67
+ sign in. After decision-14 these same fields are what their ActivityPub
68
+ actor carries, which is why they live beside the account rather than in
69
+ the site settings — and why saving them tells their followers. #}
70
+ <form class="admin-settings" method="post" action="{{ userProfileUrl }}">
71
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
72
+ <input type="hidden" name="{{ fields.userId }}" value="{{ account.id }}" />
73
+
74
+ <h2>Profile</h2>
75
+
76
+ <p class="admin-hint">
77
+ A profile is public. Nothing in it is required — a user with no profile
78
+ still has an archive under their username — and a box left empty is a
79
+ field they do not have.
80
+ </p>
81
+
82
+ {{ field.text('profile-display-name', fields.displayName, 'Display name',
83
+ account.profile.displayName,
84
+ hint='Printed instead of the login: it heads the archive and is the byline under their posts.') }}
85
+
86
+ {{ field.textarea('profile-bio', fields.bio, 'Bio', account.profile.bio, rows='4',
87
+ hint='A line or two about them, shown on the archive under the name.') }}
88
+
89
+ {% set avatarHint %}A path such as <code>/uploads/2026/09/me.jpg</code>, or a full URL.{% endset %}
90
+ {{ field.text('profile-avatar', fields.avatar, 'Avatar', account.profile.avatar,
91
+ hint=avatarHint) }}
92
+
93
+ {{ field.text('profile-job-title', fields.jobTitle, 'Job title', account.profile.jobTitle,
94
+ hint='What they do, printed beside the name on the archive.') }}
95
+
96
+ {{ field.text('profile-location', fields.location, 'Location', account.profile.location,
97
+ hint='Where they are, as they write it.') }}
98
+
99
+ {% set linksHint %}
100
+ One per line, either <code>Label | https://example.com</code> or a bare
101
+ URL that labels itself.
102
+ {% endset %}
103
+ {{ field.textarea('profile-links', fields.links, 'Links', account.profile.links, rows='4',
104
+ hint=linksHint) }}
105
+
106
+ <p class="admin-settings-buttons">
107
+ <button type="submit">Save profile</button>
108
+ </p>
109
+ </form>
110
+
111
+ {# Only once there is both somewhere to write to and something to write
112
+ with. These switches decide what is sent to the address above, so without
113
+ an address, or without a mail provider on Settings > Email, every one of
114
+ them could be on and the site would still send this person nothing. The
115
+ lines below say which is missing where the panel would have been, rather
116
+ than letting it vanish without explanation. #}
117
+ {% if account.email and mailConfigured %}
118
+ <section class="admin-settings">
119
+ <h2>Email {{ account.username }} about</h2>
120
+
121
+ <p class="admin-hint">
122
+ What this site writes to {{ account.username }} at <code>{{ account.email }}</code>.
123
+ </p>
124
+
125
+ {# One form per switch, not one form with a checkbox each: a browser sends
126
+ no field for an unticked box, so a single form could not tell "turned
127
+ this off" from "left it alone". Adding a notice is one entry in the
128
+ registry and no change here. #}
129
+ {% for notice in account.notifications %}
130
+ <div class="admin-notice">
131
+ <h3>{{ notice.label }}</h3>
132
+ <p class="admin-hint">{{ notice.description }}</p>
133
+
134
+ <form class="admin-inline" method="post" action="{{ userNotificationsUrl }}">
135
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
136
+ <input type="hidden" name="{{ fields.userId }}" value="{{ account.id }}" />
137
+ <input type="hidden" name="{{ fields.event }}" value="{{ notice.name }}" />
138
+ <input type="hidden" name="{{ fields.on }}" value="{% if notice.on %}{% else %}1{% endif %}" />
139
+ <span class="admin-status">{% if notice.on %}On{% else %}Off{% endif %}</span>
140
+ <button type="submit">{% if notice.on %}Turn off{% else %}Turn on{% endif %}</button>
141
+ </form>
142
+
143
+ {# And, for a notice the registry says can be batched, how often it
144
+ should arrive. A second form because a select needs a Save beside
145
+ it and the switch above is a button; the registry decides which
146
+ notices get one. #}
147
+ {% if notice.batched %}
148
+ <form class="admin-inline" method="post" action="{{ userNotificationModeUrl }}">
149
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
150
+ <input type="hidden" name="{{ fields.userId }}" value="{{ account.id }}" />
151
+ <input type="hidden" name="{{ fields.event }}" value="{{ notice.name }}" />
152
+ {% call field.select('notice-mode-' + notice.name, fields.mode, 'How often') %}
153
+ {% for choice in notice.modes %}
154
+ <option value="{{ choice.value }}"{% if choice.chosen %} selected{% endif %}>{{ choice.label }}</option>
155
+ {% endfor %}
156
+ {% endcall %}
157
+ <button type="submit">Save</button>
158
+ </form>
159
+ <p class="admin-hint">
160
+ On an hourly or a daily digest nothing is sent as they arrive;
161
+ instead one message a window lists everything still waiting, and
162
+ no message goes at all when nothing is.
163
+ </p>
164
+ {% endif %}
165
+ </div>
166
+ {% endfor %}
167
+ </section>
168
+ {% else %}
169
+ <section class="admin-settings">
170
+ <h2>Email {{ account.username }} about</h2>
171
+
172
+ {% if not mailConfigured %}
173
+ <p class="admin-hint">
174
+ Nothing, while this site has no mail provider: there is nothing to send
175
+ with. Choose one on <a href="{{ adminUrl }}/settings/email">Settings
176
+ &rsaquo; Email</a> and what to send comes back here.
177
+ </p>
178
+ {% else %}
179
+ <p class="admin-hint">
180
+ Nothing, while the box above is empty: there is nowhere to write to.
181
+ Give {% if account.you %}yourself{% else %}this account{% endif %} an
182
+ address and what to send comes back here.
183
+ </p>
184
+ {% endif %}
185
+ </section>
186
+ {% endif %}
187
+
188
+ {# Only on your own page: it asks for the current password, so it is about
189
+ whoever is signed in and means nothing on somebody else's screen.
190
+ Resetting a colleague's password from under them is deliberately not
191
+ offered — a fresh account is what that is for. #}
192
+ {% if account.you %}
193
+ <form class="admin-settings" method="post" action="{{ changePasswordUrl }}">
194
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
195
+
196
+ <h2>Change your password</h2>
197
+
198
+ {% if passwordProblems.currentPassword or passwordProblems.newPassword %}
199
+ <p class="admin-error">Your password was not changed. Fix the fields marked below and try again.</p>
200
+ {% endif %}
201
+
202
+ {{ field.password('current-password', fields.currentPassword, 'Current password',
203
+ error=passwordProblems.currentPassword, autocomplete='current-password',
204
+ required=true) }}
205
+
206
+ {{ field.password('new-password', fields.newPassword, 'New password',
207
+ error=passwordProblems.newPassword, autocomplete='new-password', required=true) }}
208
+
209
+ {{ field.password('new-password-confirmation', fields.newPasswordConfirmation,
210
+ 'New password again', autocomplete='new-password', required=true) }}
211
+
212
+ <p class="admin-hint">Every other browser signed in as you is signed out. This one stays.</p>
213
+
214
+ <p class="admin-settings-buttons">
215
+ <button type="submit">Change password</button>
216
+ </p>
217
+ </form>
218
+ {% endif %}
219
+
220
+ <section class="admin-settings">
221
+ <h2>Delete</h2>
222
+
223
+ {# Either the button or the reason there is none, never both: the screen
224
+ does not offer an action it is about to refuse. #}
225
+ {% if deleteRefusal %}
226
+ <p class="admin-hint">{{ deleteRefusal }}</p>
227
+ {% else %}
228
+ <p class="admin-hint">
229
+ Deleting {{ account.username }} signs out every browser they are in and
230
+ cannot be undone. What they have written stays where it is.
231
+ </p>
232
+ <form method="post" action="{{ deleteUserUrl }}">
233
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
234
+ <input type="hidden" name="{{ fields.userId }}" value="{{ account.id }}" />
235
+ <button type="submit">Delete {{ account.username }}</button>
236
+ </form>
237
+ {% endif %}
238
+ </section>
239
+ {% endblock %}
@@ -0,0 +1,48 @@
1
+ {# /admin/users: who can sign in.
2
+
3
+ A listing and nothing else (TASK-97). Every field a user has is edited on
4
+ that user's own screen, which the Edit link in each row goes to, so no box
5
+ in this table can be mistaken for another one. Adding somebody is its own
6
+ screen next door, `new.njk`, because Users > Add new is its own menu entry.
7
+ #}
8
+ {% extends "layouts/shell.njk" %}
9
+
10
+ {% block title %}Users{% endblock %}
11
+
12
+ {% block content %}
13
+ <h1>Users <a class="admin-button admin-button-small" href="{{ addUserUrl }}">Add new</a></h1>
14
+
15
+ <table class="admin-list">
16
+ <thead>
17
+ <tr>
18
+ <th scope="col">Username</th>
19
+ <th scope="col">Email</th>
20
+ <th scope="col">Created</th>
21
+ <th scope="col">Actions</th>
22
+ </tr>
23
+ </thead>
24
+ <tbody>
25
+ {% for entry in users %}
26
+ <tr>
27
+ <td>
28
+ <a href="{{ entry.editUrl }}">{{ entry.username }}</a>{% if entry.you %} <span class="admin-status">(you)</span>{% endif %}
29
+ <br /><a href="{{ entry.archiveUrl }}">{{ entry.archiveUrl }}</a>
30
+ </td>
31
+ <td>{% if entry.email %}{{ entry.email }}{% else %}<span class="admin-status">None</span>{% endif %}</td>
32
+ <td>{{ entry.createdAt | date('html') }}</td>
33
+ <td class="admin-actions">
34
+ <a class="admin-button admin-button-small" href="{{ entry.editUrl }}">Edit</a>
35
+ {% if entry.deletable %}
36
+ <form method="post" action="{{ deleteUserUrl }}">
37
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
38
+ <input type="hidden" name="{{ fields.userId }}" value="{{ entry.id }}" />
39
+ <button type="submit">Delete</button>
40
+ </form>
41
+ {% endif %}
42
+ </td>
43
+ </tr>
44
+ {% endfor %}
45
+ </tbody>
46
+ </table>
47
+
48
+ {% endblock %}
@@ -0,0 +1,41 @@
1
+ {# /admin/users/new: add somebody who can sign in.
2
+
3
+ The other half of what the listing used to hold: one form, the same chrome,
4
+ and its own menu entry under Users. A refused add comes back here with what
5
+ was typed still in the boxes, so nothing is retyped to fix one field.
6
+ #}
7
+ {% extends "layouts/shell.njk" %}
8
+ {% import "components/fields.njk" as field %}
9
+
10
+ {% block title %}Add new user{% endblock %}
11
+
12
+ {% block content %}
13
+ <h1>Add new user</h1>
14
+
15
+ <form class="admin-settings" method="post" action="{{ addUserUrl }}">
16
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
17
+
18
+ {% if addProblems.username or addProblems.password or addProblems.email %}
19
+ <p class="admin-error">Nobody was added. Fix the fields marked below and try again.</p>
20
+ {% endif %}
21
+
22
+ {{ field.text('add-username', fields.username, 'Username', addForm.username,
23
+ error=addProblems.username, required=true) }}
24
+
25
+ {{ field.text('add-email', fields.email, 'Email <span class="admin-status">(optional)</span>',
26
+ addForm.email, type='email', autocomplete='email', error=addProblems.email) }}
27
+
28
+ {{ field.password('add-password', fields.password, 'Password',
29
+ error=addProblems.password, autocomplete='new-password') }}
30
+
31
+ {{ field.checkbox('add-generate', fields.generate,
32
+ 'Generate one instead, and show it to me once', checked=addForm.generate,
33
+ hint='A generated password is shown on the next page and nowhere else. Copy it before you leave.') }}
34
+
35
+ <p class="admin-settings-buttons">
36
+ <button type="submit">Add user</button>
37
+ </p>
38
+ </form>
39
+
40
+ <p class="admin-hint"><a href="{{ usersUrl }}">Back to all users</a></p>
41
+ {% endblock %}