@geekity/cms 0.21.0 → 0.23.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 (302) hide show
  1. package/README.md +42 -4
  2. package/admin/components/admin-bar.njk +27 -6
  3. package/admin/components/alert.njk +28 -0
  4. package/admin/components/badge.njk +58 -0
  5. package/admin/components/button.njk +56 -0
  6. package/admin/components/card.njk +40 -0
  7. package/admin/components/collapse.njk +36 -0
  8. package/admin/components/copy.njk +20 -0
  9. package/admin/components/dropdown.njk +32 -0
  10. package/admin/components/fields.njk +81 -45
  11. package/admin/components/flash.njk +12 -5
  12. package/admin/components/menu.njk +51 -0
  13. package/admin/components/navbar.njk +23 -0
  14. package/admin/components/pagination.njk +47 -0
  15. package/admin/components/public-admin-bar.njk +4 -41
  16. package/admin/components/stat.njk +35 -0
  17. package/admin/components/table.njk +74 -0
  18. package/admin/components/tabs.njk +33 -0
  19. package/admin/components/theme-choice.njk +18 -0
  20. package/admin/layouts/base.njk +9 -16
  21. package/admin/layouts/settings-page.njk +15 -10
  22. package/admin/layouts/shell.njk +23 -31
  23. package/admin/pages/account/forgot.njk +39 -33
  24. package/admin/pages/account/login.njk +22 -16
  25. package/admin/pages/account/reset.njk +34 -25
  26. package/admin/pages/account/setup.njk +21 -15
  27. package/admin/pages/appearance/themes.njk +50 -44
  28. package/admin/pages/comments/all.njk +88 -106
  29. package/admin/pages/dashboard/home.njk +50 -62
  30. package/admin/pages/documents/conflict.njk +29 -24
  31. package/admin/pages/documents/editor.njk +173 -275
  32. package/admin/pages/documents/list.njk +60 -69
  33. package/admin/pages/documents/syndication.njk +98 -60
  34. package/admin/pages/documents/taxonomy.njk +36 -32
  35. package/admin/pages/error.njk +8 -5
  36. package/admin/pages/federation/followers.njk +91 -97
  37. package/admin/pages/federation/settings.njk +10 -11
  38. package/admin/pages/indieauth/consent.njk +60 -44
  39. package/admin/pages/indieauth/refused.njk +6 -3
  40. package/admin/pages/media/library.njk +86 -107
  41. package/admin/pages/messages/all.njk +71 -77
  42. package/admin/pages/navigation/menus.njk +90 -85
  43. package/admin/pages/placeholder.njk +13 -8
  44. package/admin/pages/settings/discussion.njk +30 -29
  45. package/admin/pages/settings/email.njk +26 -28
  46. package/admin/pages/settings/general.njk +10 -4
  47. package/admin/pages/settings/permalinks.njk +8 -9
  48. package/admin/pages/settings/privacy.njk +3 -3
  49. package/admin/pages/settings/reading.njk +3 -3
  50. package/admin/pages/tools/content-index.njk +79 -73
  51. package/admin/pages/tools/personal-data.njk +61 -55
  52. package/admin/pages/users/activity-entry.njk +12 -12
  53. package/admin/pages/users/activity.njk +13 -19
  54. package/admin/pages/users/apps.njk +112 -100
  55. package/admin/pages/users/edit.njk +65 -58
  56. package/admin/pages/users/list.njk +26 -24
  57. package/admin/pages/users/new.njk +11 -7
  58. package/admin/src/admin.css +174 -0
  59. package/admin/static/admin-bar.css +33 -31
  60. package/admin/static/admin-bar.js +22 -0
  61. package/admin/static/admin.css +7388 -1195
  62. package/admin/static/copy.js +1 -1
  63. package/admin/static/editor.js +18 -18
  64. package/dist/admin/accounts.d.ts +20 -0
  65. package/dist/admin/accounts.d.ts.map +1 -1
  66. package/dist/admin/accounts.js +25 -0
  67. package/dist/admin/accounts.js.map +1 -1
  68. package/dist/admin/admin-theme.d.ts +157 -0
  69. package/dist/admin/admin-theme.d.ts.map +1 -0
  70. package/dist/admin/admin-theme.js +52 -0
  71. package/dist/admin/admin-theme.js.map +1 -0
  72. package/dist/admin/assets.d.ts +4 -3
  73. package/dist/admin/assets.d.ts.map +1 -1
  74. package/dist/admin/assets.js +4 -3
  75. package/dist/admin/assets.js.map +1 -1
  76. package/dist/admin/comments.js +2 -2
  77. package/dist/admin/comments.js.map +1 -1
  78. package/dist/admin/documents.d.ts +36 -7
  79. package/dist/admin/documents.d.ts.map +1 -1
  80. package/dist/admin/documents.js +141 -30
  81. package/dist/admin/documents.js.map +1 -1
  82. package/dist/admin/editor-layout.d.ts +1 -1
  83. package/dist/admin/editor-layout.d.ts.map +1 -1
  84. package/dist/admin/editor-layout.js +6 -1
  85. package/dist/admin/editor-layout.js.map +1 -1
  86. package/dist/admin/event-field.d.ts +26 -0
  87. package/dist/admin/event-field.d.ts.map +1 -0
  88. package/dist/admin/event-field.js +74 -0
  89. package/dist/admin/event-field.js.map +1 -0
  90. package/dist/admin/federation.js +3 -3
  91. package/dist/admin/federation.js.map +1 -1
  92. package/dist/admin/headers.js +1 -1
  93. package/dist/admin/headers.js.map +1 -1
  94. package/dist/admin/media.js +2 -2
  95. package/dist/admin/media.js.map +1 -1
  96. package/dist/admin/preview.d.ts.map +1 -1
  97. package/dist/admin/preview.js +16 -1
  98. package/dist/admin/preview.js.map +1 -1
  99. package/dist/admin/routes.d.ts.map +1 -1
  100. package/dist/admin/routes.js +17 -8
  101. package/dist/admin/routes.js.map +1 -1
  102. package/dist/admin/store.d.ts +9 -0
  103. package/dist/admin/store.d.ts.map +1 -1
  104. package/dist/admin/store.js +16 -5
  105. package/dist/admin/store.js.map +1 -1
  106. package/dist/admin/templates.d.ts +6 -3
  107. package/dist/admin/templates.d.ts.map +1 -1
  108. package/dist/admin/templates.js +25 -3
  109. package/dist/admin/templates.js.map +1 -1
  110. package/dist/admin/users.d.ts +4 -0
  111. package/dist/admin/users.d.ts.map +1 -1
  112. package/dist/admin/users.js +37 -1
  113. package/dist/admin/users.js.map +1 -1
  114. package/dist/avatars/avatars.js +1 -1
  115. package/dist/avatars/avatars.js.map +1 -1
  116. package/dist/comments/policy.d.ts +10 -0
  117. package/dist/comments/policy.d.ts.map +1 -1
  118. package/dist/comments/policy.js +12 -0
  119. package/dist/comments/policy.js.map +1 -1
  120. package/dist/comments/records.d.ts +5 -1
  121. package/dist/comments/records.d.ts.map +1 -1
  122. package/dist/comments/records.js +16 -2
  123. package/dist/comments/records.js.map +1 -1
  124. package/dist/content/event.d.ts +40 -0
  125. package/dist/content/event.d.ts.map +1 -0
  126. package/dist/content/event.js +51 -0
  127. package/dist/content/event.js.map +1 -0
  128. package/dist/content/handles.d.ts +22 -0
  129. package/dist/content/handles.d.ts.map +1 -0
  130. package/dist/content/handles.js +68 -0
  131. package/dist/content/handles.js.map +1 -0
  132. package/dist/content/markdown.d.ts +8 -2
  133. package/dist/content/markdown.d.ts.map +1 -1
  134. package/dist/content/markdown.js +55 -5
  135. package/dist/content/markdown.js.map +1 -1
  136. package/dist/content/parser.d.ts +3 -0
  137. package/dist/content/parser.d.ts.map +1 -1
  138. package/dist/content/parser.js +1 -1
  139. package/dist/content/parser.js.map +1 -1
  140. package/dist/content/post-type.d.ts +12 -8
  141. package/dist/content/post-type.d.ts.map +1 -1
  142. package/dist/content/post-type.js +19 -4
  143. package/dist/content/post-type.js.map +1 -1
  144. package/dist/content/rsvp.d.ts +29 -0
  145. package/dist/content/rsvp.d.ts.map +1 -0
  146. package/dist/content/rsvp.js +49 -0
  147. package/dist/content/rsvp.js.map +1 -0
  148. package/dist/content/save.d.ts +2 -1
  149. package/dist/content/save.d.ts.map +1 -1
  150. package/dist/content/save.js +10 -3
  151. package/dist/content/save.js.map +1 -1
  152. package/dist/content/store.d.ts +11 -4
  153. package/dist/content/store.d.ts.map +1 -1
  154. package/dist/content/store.js +15 -4
  155. package/dist/content/store.js.map +1 -1
  156. package/dist/content/sync.d.ts.map +1 -1
  157. package/dist/content/sync.js +7 -6
  158. package/dist/content/sync.js.map +1 -1
  159. package/dist/env.d.ts +3 -0
  160. package/dist/env.d.ts.map +1 -1
  161. package/dist/federation/article.d.ts +9 -3
  162. package/dist/federation/article.d.ts.map +1 -1
  163. package/dist/federation/article.js +90 -34
  164. package/dist/federation/article.js.map +1 -1
  165. package/dist/federation/cited-post.d.ts +13 -0
  166. package/dist/federation/cited-post.d.ts.map +1 -0
  167. package/dist/federation/cited-post.js +75 -0
  168. package/dist/federation/cited-post.js.map +1 -0
  169. package/dist/federation/delivery.d.ts.map +1 -1
  170. package/dist/federation/delivery.js +31 -2
  171. package/dist/federation/delivery.js.map +1 -1
  172. package/dist/federation/handles.d.ts +28 -0
  173. package/dist/federation/handles.d.ts.map +1 -0
  174. package/dist/federation/handles.js +65 -0
  175. package/dist/federation/handles.js.map +1 -0
  176. package/dist/federation/inbox.d.ts +2 -1
  177. package/dist/federation/inbox.d.ts.map +1 -1
  178. package/dist/federation/inbox.js +11 -3
  179. package/dist/federation/inbox.js.map +1 -1
  180. package/dist/federation/mount.d.ts.map +1 -1
  181. package/dist/federation/mount.js +18 -2
  182. package/dist/federation/mount.js.map +1 -1
  183. package/dist/federation/profiles.d.ts.map +1 -1
  184. package/dist/federation/profiles.js +2 -8
  185. package/dist/federation/profiles.js.map +1 -1
  186. package/dist/federation/site-loaders.d.ts +15 -0
  187. package/dist/federation/site-loaders.d.ts.map +1 -0
  188. package/dist/federation/site-loaders.js +19 -0
  189. package/dist/federation/site-loaders.js.map +1 -0
  190. package/dist/index.d.ts.map +1 -1
  191. package/dist/index.js +23 -1
  192. package/dist/index.js.map +1 -1
  193. package/dist/indieauth/client.js +2 -2
  194. package/dist/indieauth/client.js.map +1 -1
  195. package/dist/micropub/create.d.ts +2 -1
  196. package/dist/micropub/create.d.ts.map +1 -1
  197. package/dist/micropub/create.js +57 -8
  198. package/dist/micropub/create.js.map +1 -1
  199. package/dist/micropub/endpoint.d.ts.map +1 -1
  200. package/dist/micropub/endpoint.js +12 -4
  201. package/dist/micropub/endpoint.js.map +1 -1
  202. package/dist/micropub/update.d.ts +3 -0
  203. package/dist/micropub/update.d.ts.map +1 -1
  204. package/dist/micropub/update.js +29 -4
  205. package/dist/micropub/update.js.map +1 -1
  206. package/dist/web/admin-bar.d.ts +4 -4
  207. package/dist/web/admin-bar.d.ts.map +1 -1
  208. package/dist/web/admin-bar.js +11 -34
  209. package/dist/web/admin-bar.js.map +1 -1
  210. package/dist/web/context.d.ts +32 -4
  211. package/dist/web/context.d.ts.map +1 -1
  212. package/dist/web/context.js +28 -1
  213. package/dist/web/context.js.map +1 -1
  214. package/dist/web/conversation.d.ts +26 -1
  215. package/dist/web/conversation.d.ts.map +1 -1
  216. package/dist/web/conversation.js +67 -10
  217. package/dist/web/conversation.js.map +1 -1
  218. package/dist/web/documents.d.ts +12 -0
  219. package/dist/web/documents.d.ts.map +1 -1
  220. package/dist/web/documents.js +20 -0
  221. package/dist/web/documents.js.map +1 -1
  222. package/dist/web/feed-item.d.ts.map +1 -1
  223. package/dist/web/feed-item.js +8 -3
  224. package/dist/web/feed-item.js.map +1 -1
  225. package/dist/web/render.d.ts +3 -0
  226. package/dist/web/render.d.ts.map +1 -1
  227. package/dist/web/render.js +39 -6
  228. package/dist/web/render.js.map +1 -1
  229. package/dist/web/routes.d.ts.map +1 -1
  230. package/dist/web/routes.js +16 -3
  231. package/dist/web/routes.js.map +1 -1
  232. package/dist/web/templates.d.ts +4 -1
  233. package/dist/web/templates.d.ts.map +1 -1
  234. package/dist/web/templates.js +11 -0
  235. package/dist/web/templates.js.map +1 -1
  236. package/dist/webmention/cited-picture.d.ts +11 -4
  237. package/dist/webmention/cited-picture.d.ts.map +1 -1
  238. package/dist/webmention/cited-picture.js +22 -13
  239. package/dist/webmention/cited-picture.js.map +1 -1
  240. package/dist/webmention/cited-start.d.ts +10 -0
  241. package/dist/webmention/cited-start.d.ts.map +1 -0
  242. package/dist/webmention/cited-start.js +21 -0
  243. package/dist/webmention/cited-start.js.map +1 -0
  244. package/dist/webmention/fetch-public.d.ts +2 -2
  245. package/dist/webmention/fetch-public.d.ts.map +1 -1
  246. package/dist/webmention/fetch-public.js +1 -1
  247. package/dist/webmention/fetch-public.js.map +1 -1
  248. package/dist/webmention/html.d.ts +2 -0
  249. package/dist/webmention/html.d.ts.map +1 -1
  250. package/dist/webmention/html.js +6 -0
  251. package/dist/webmention/html.js.map +1 -1
  252. package/dist/webmention/index.d.ts +2 -1
  253. package/dist/webmention/index.d.ts.map +1 -1
  254. package/dist/webmention/index.js +1 -0
  255. package/dist/webmention/index.js.map +1 -1
  256. package/dist/webmention/microformats.d.ts +25 -2
  257. package/dist/webmention/microformats.d.ts.map +1 -1
  258. package/dist/webmention/microformats.js +38 -4
  259. package/dist/webmention/microformats.js.map +1 -1
  260. package/dist/webmention/pingback.d.ts +42 -0
  261. package/dist/webmention/pingback.d.ts.map +1 -0
  262. package/dist/webmention/pingback.js +229 -0
  263. package/dist/webmention/pingback.js.map +1 -0
  264. package/dist/webmention/receive.d.ts +20 -2
  265. package/dist/webmention/receive.d.ts.map +1 -1
  266. package/dist/webmention/receive.js +25 -16
  267. package/dist/webmention/receive.js.map +1 -1
  268. package/dist/webmention/reply-context.d.ts +65 -18
  269. package/dist/webmention/reply-context.d.ts.map +1 -1
  270. package/dist/webmention/reply-context.js +403 -99
  271. package/dist/webmention/reply-context.js.map +1 -1
  272. package/dist/webmention/reply-contexts.d.ts +3 -1
  273. package/dist/webmention/reply-contexts.d.ts.map +1 -1
  274. package/dist/webmention/reply-contexts.js +53 -17
  275. package/dist/webmention/reply-contexts.js.map +1 -1
  276. package/dist/webmention/routes.d.ts.map +1 -1
  277. package/dist/webmention/routes.js +2 -0
  278. package/dist/webmention/routes.js.map +1 -1
  279. package/dist/webmention/service.d.ts +11 -0
  280. package/dist/webmention/service.d.ts.map +1 -1
  281. package/dist/webmention/service.js +27 -6
  282. package/dist/webmention/service.js.map +1 -1
  283. package/dist/webmention/syndication.d.ts +6 -0
  284. package/dist/webmention/syndication.d.ts.map +1 -1
  285. package/dist/webmention/syndication.js +12 -0
  286. package/dist/webmention/syndication.js.map +1 -1
  287. package/package.json +10 -6
  288. package/themes/default/README.md +130 -38
  289. package/themes/default/layouts/410.njk +10 -0
  290. package/themes/default/layouts/base.njk +3 -0
  291. package/themes/default/layouts/page.njk +7 -0
  292. package/themes/default/layouts/post.njk +7 -4
  293. package/themes/default/layouts/search.njk +1 -1
  294. package/themes/default/partials/cited-page.njk +7 -0
  295. package/themes/default/partials/conversation.njk +25 -5
  296. package/themes/default/partials/event.njk +27 -0
  297. package/themes/default/partials/jsonld.njk +28 -0
  298. package/themes/default/partials/post-list.njk +5 -2
  299. package/themes/default/partials/reply-context.njk +24 -4
  300. package/themes/default/partials/rsvp.njk +7 -0
  301. package/themes/default/src/style.css +20 -0
  302. package/themes/default/static/style.css +35 -0
@@ -1,46 +1,51 @@
1
1
  {# /admin/federation: who this site's people are to the fediverse, who follows
2
2
  each of them, what arrived in the inbox, and how what went out landed. #}
3
3
  {% extends "layouts/shell.njk" %}
4
+ {% from "components/badge.njk" import status %}
5
+ {% from "components/button.njk" import button %}
6
+ {% from "components/card.njk" import card %}
7
+ {% from "components/table.njk" import table %}
4
8
 
5
9
  {% block title %}Federation{% endblock %}
6
10
 
11
+ {% set AVATAR_SIZES = { large: 'w-24', small: 'w-8' } %}
12
+ {% macro avatar(url, size) %}
13
+ {% if url %}
14
+ <div class="avatar shrink-0">
15
+ <div class="rounded-full{{ AVATAR_SIZES | modifier(size) }}">
16
+ <img class="object-cover" src="{{ url }}" alt="" width="{{ 96 if size == 'large' else 32 }}" height="{{ 96 if size == 'large' else 32 }}" loading="lazy" />
17
+ </div>
18
+ </div>
19
+ {% else %}
20
+ <div class="avatar avatar-placeholder shrink-0" aria-hidden="true">
21
+ <div class="rounded-full bg-base-300{{ AVATAR_SIZES | modifier(size) }}"></div>
22
+ </div>
23
+ {% endif %}
24
+ {% endmacro %}
25
+
7
26
  {% block content %}
8
- <h1>Federation</h1>
27
+ <h1 class="mb-6 text-2xl font-bold">Federation</h1>
9
28
 
10
- {% if actors.length %}
29
+ <div class="mb-10 grid grid-cols-1 gap-6">
11
30
  {% for actor in actors %}
12
- <section class="admin-panel admin-actor">
13
- <h2>{{ actor.handle }}</h2>
14
- <div class="admin-actor-identity">
15
- {% if actor.avatarUrl %}
16
- <img class="admin-avatar admin-avatar-large" src="{{ actor.avatarUrl }}" alt="" width="96" height="96" />
17
- {% else %}
18
- <span class="admin-avatar admin-avatar-large admin-avatar-blank" aria-hidden="true"></span>
19
- {% endif %}
20
- <p class="admin-actor-handle">{{ actor.name }}</p>
31
+ {% call card(title=actor.handle) %}
32
+ <div class="flex items-center gap-4">
33
+ {{ avatar(actor.avatarUrl, 'large') }}
34
+ <p class="text-lg">{{ actor.name }}</p>
21
35
  </div>
22
- <dl class="admin-actor-fields">
23
- <div>
24
- <dt>Summary</dt>
25
- <dd>{% if actor.summary %}{{ actor.summary }}{% else %}<span class="admin-empty">None set.</span>{% endif %}</dd>
26
- </div>
27
- <div>
28
- <dt>Actor</dt>
29
- <dd><a href="{{ actor.actorId }}">{{ actor.actorId }}</a></dd>
30
- </div>
31
- <div>
32
- <dt>Profile</dt>
33
- <dd><a href="{{ actor.url }}">{{ actor.url }}</a></dd>
34
- </div>
35
- <div>
36
- <dt>Followers</dt>
37
- <dd>{{ actor.followerCount }}</dd>
38
- </div>
36
+ <dl class="grid grid-cols-[auto_1fr] gap-x-4 gap-y-1">
37
+ <dt>Summary</dt>
38
+ <dd>{{ actor.summary or 'None set.' }}</dd>
39
+ <dt>Actor</dt>
40
+ <dd><a class="link break-all" href="{{ actor.actorId }}">{{ actor.actorId }}</a></dd>
41
+ <dt>Profile</dt>
42
+ <dd><a class="link break-all" href="{{ actor.url }}">{{ actor.url }}</a></dd>
43
+ <dt>Followers</dt>
44
+ <dd>{{ actor.followerCount }}</dd>
39
45
  </dl>
40
46
 
41
47
  {% if actor.followers.length %}
42
- <table class="admin-list">
43
- <caption>Followers of {{ actor.handle }}</caption>
48
+ {% call table('Followers of ' + actor.handle, inCard=true) %}
44
49
  <thead>
45
50
  <tr>
46
51
  <th scope="col">Follower</th>
@@ -51,37 +56,33 @@
51
56
  <tbody>
52
57
  {% for follower in actor.followers %}
53
58
  <tr>
54
- <td class="admin-follower">
55
- {% if follower.iconUrl %}
56
- <img class="admin-avatar" src="{{ follower.iconUrl }}" alt="" width="32" height="32" loading="lazy" />
57
- {% else %}
58
- <span class="admin-avatar admin-avatar-blank" aria-hidden="true"></span>
59
- {% endif %}
60
- <a href="{{ follower.url }}">{{ follower.name }}</a>
59
+ <td>
60
+ <div class="flex items-center gap-2">
61
+ {{ avatar(follower.iconUrl, 'small') }}
62
+ <a class="link link-hover" href="{{ follower.url }}">{{ follower.name }}</a>
63
+ </div>
61
64
  </td>
62
65
  <td>{{ follower.handle }}</td>
63
- <td>{{ follower.followedAt | date('html') }}</td>
66
+ <td class="whitespace-nowrap">{{ follower.followedAt | date('html') }}</td>
64
67
  </tr>
65
68
  {% endfor %}
66
69
  </tbody>
67
- </table>
70
+ {% endcall %}
68
71
  {% else %}
69
- <p class="admin-empty">Nobody follows {{ actor.name }} yet.</p>
72
+ <p>Nobody follows {{ actor.name }} yet.</p>
70
73
  {% endif %}
71
- </section>
74
+ {% endcall %}
75
+ {% else %}
76
+ {% call card(title='Actors') %}
77
+ <p>The site has no users, so it has no actors.</p>
78
+ {% endcall %}
72
79
  {% endfor %}
73
- {% else %}
74
- <section class="admin-panel admin-actor">
75
- <h2>Actors</h2>
76
- <p class="admin-empty">The site has no users, so it has no actors.</p>
77
- </section>
78
- {% endif %}
80
+ </div>
79
81
 
80
- <section class="admin-panel">
81
- <h2>Relays</h2>
82
+ <section class="mb-10">
83
+ <h2 class="mb-3 text-lg font-semibold">Relays</h2>
82
84
  {% if relays.length %}
83
- <table class="admin-list">
84
- <caption class="admin-visually-hidden">Relays</caption>
85
+ {% call table('Relays') %}
85
86
  <thead>
86
87
  <tr>
87
88
  <th scope="col">Relay</th>
@@ -96,87 +97,80 @@
96
97
  <tr>
97
98
  <td>
98
99
  {% if relay.actorId %}
99
- <a href="{{ relay.actorId }}">{{ relay.inboxId }}</a>
100
+ <a class="link link-hover" href="{{ relay.actorId }}">{{ relay.inboxId }}</a>
100
101
  {% else %}
101
102
  {{ relay.inboxId }}
102
103
  {% endif %}
103
104
  {% if relay.reason %}
104
- <p class="admin-hint">{{ relay.reason }}</p>
105
+ <p class="text-sm">{{ relay.reason }}</p>
105
106
  {% endif %}
106
107
  </td>
107
- <td>
108
- {% if relay.state == 'rejected' %}
109
- <span class="admin-status admin-status-failed">{{ relay.stateLabel }}</span>
110
- {% else %}
111
- {{ relay.stateLabel }}
112
- {% endif %}
113
- </td>
114
- <td>{{ relay.updatedAt | date('html') }}</td>
108
+ <td>{{ status(relay.state, relay.stateLabel) }}</td>
109
+ <td class="whitespace-nowrap">{{ relay.updatedAt | date('html') }}</td>
115
110
  <td>
116
111
  {% if relay.lastDelivery %}
117
112
  {{ relay.lastDelivery.activityType }} {{ relay.lastDelivery.status }}
118
- <span class="admin-inbox-when">{{ relay.lastDelivery.attemptedAt | date('html') }}</span>
113
+ <span class="whitespace-nowrap text-sm">{{ relay.lastDelivery.attemptedAt | date('html') }}</span>
119
114
  {% if relay.lastDelivery.error %}
120
- <p class="admin-hint">{{ relay.lastDelivery.error }}</p>
115
+ <p class="text-sm">{{ relay.lastDelivery.error }}</p>
121
116
  {% endif %}
122
117
  {% else %}
123
- <span class="admin-empty">Nothing yet.</span>
118
+ Nothing yet.
124
119
  {% endif %}
125
120
  </td>
126
- <td class="admin-actions">
121
+ <td>
127
122
  {% if relay.retriable %}
128
123
  <form method="post" action="{{ relayRetryUrl }}">
129
124
  <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
130
125
  <input type="hidden" name="{{ fields.relay }}" value="{{ relay.inboxId }}" />
131
- <button type="submit">Retry</button>
126
+ {{ button('Retry', type='submit', style='ghost', size='xs') }}
132
127
  </form>
133
128
  {% endif %}
134
129
  </td>
135
130
  </tr>
136
131
  {% endfor %}
137
132
  </tbody>
138
- </table>
139
- <p class="admin-hint">
133
+ {% endcall %}
134
+ <p class="mt-4 max-w-prose text-sm">
140
135
  A relay boosts every public post it is sent on to instances nobody here
141
136
  follows. The list lives on the Settings screen; Retry sends the follow
142
137
  again to one that is still waiting.
143
138
  </p>
144
139
  {% else %}
145
- <p class="admin-empty">The site subscribes to no relay. Add one on the Settings screen.</p>
140
+ <p>The site subscribes to no relay. Add one on the Settings screen.</p>
146
141
  {% endif %}
147
142
  </section>
148
143
 
149
- <section class="admin-panel">
150
- <h2>Recent activity</h2>
144
+ <section class="mb-10">
145
+ <h2 class="mb-3 text-lg font-semibold">Recent activity</h2>
151
146
  {% if inbox.length %}
152
- <ul class="admin-inbox">
147
+ <ul class="space-y-1">
153
148
  {% for entry in inbox %}
154
149
  <li>
155
- <span class="admin-inbox-actor"><a href="{{ entry.actorId }}">{{ entry.actorLabel }}</a></span>
150
+ <a class="link link-hover font-medium" href="{{ entry.actorId }}">{{ entry.actorLabel }}</a>
156
151
  {% if entry.remoteUrl %}
157
- <a href="{{ entry.remoteUrl }}">{{ entry.action }}</a>
152
+ <a class="link" href="{{ entry.remoteUrl }}">{{ entry.action }}</a>
158
153
  {% else %}
159
154
  {{ entry.action }}
160
155
  {% endif %}
161
156
  {% if entry.post %}
162
- <a href="{{ entry.post.editUrl }}">{{ entry.post.title }}</a>
157
+ <a class="link" href="{{ entry.post.editUrl }}">{{ entry.post.title }}</a>
163
158
  {% else %}
164
- <span class="admin-empty">something of ours</span>
159
+ <em>something of ours</em>
165
160
  {% endif %}
166
- <span class="admin-inbox-when">{{ entry.receivedAt | date('html') }}</span>
161
+ <span class="whitespace-nowrap text-sm">{{ entry.receivedAt | date('html') }}</span>
167
162
  </li>
168
163
  {% endfor %}
169
164
  </ul>
170
165
  {% else %}
171
- <p class="admin-empty">Nothing has arrived yet: no likes, boosts or replies.</p>
166
+ <p>Nothing has arrived yet: no likes, boosts or replies.</p>
172
167
  {% endif %}
173
168
  </section>
174
169
 
175
- <section class="admin-panel">
176
- <h2>Delivery</h2>
170
+ <section>
171
+ <h2 class="mb-3 text-lg font-semibold">Delivery</h2>
177
172
  {% if posts.length %}
178
- <table class="admin-list">
179
- <caption class="admin-visually-hidden">Delivery</caption>
173
+ {% call table('Delivery') %}
180
174
  <thead>
181
175
  <tr>
182
176
  <th scope="col">Post</th>
@@ -193,47 +187,47 @@
193
187
  {% for row in posts %}
194
188
  <tr>
195
189
  <td>
196
- <a href="{{ row.post.editUrl }}">{{ row.post.title }}</a>
197
- {% if row.trashed %}<p class="admin-hint">In the trash.</p>{% endif %}
190
+ <a class="link link-hover font-medium" href="{{ row.post.editUrl }}">{{ row.post.title }}</a>
191
+ {% if row.trashed %}<p class="text-sm">In the trash.</p>{% endif %}
198
192
  </td>
199
- <td>{% if row.author %}@{{ row.author }}{% else %}<span class="admin-empty">—</span>{% endif %}</td>
193
+ <td>{% if row.author %}@{{ row.author }}{% else %}—{% endif %}</td>
200
194
  {% if row.lastActivity %}
201
- <td>{{ row.lastActivity.activityType }} <span class="admin-inbox-when">{{ row.lastActivity.attemptedAt | date('html') }}</span></td>
195
+ <td>{{ row.lastActivity.activityType }} <span class="whitespace-nowrap text-sm">{{ row.lastActivity.attemptedAt | date('html') }}</span></td>
202
196
  <td>{{ row.lastActivity.counts.sent }}</td>
203
197
  <td>{{ row.lastActivity.counts.queued }}</td>
204
- <td>{% if row.lastActivity.counts.failed %}<span class="admin-status admin-status-failed">{{ row.lastActivity.counts.failed }}</span>{% else %}0{% endif %}</td>
198
+ <td class="whitespace-nowrap">{% if row.lastActivity.counts.failed %}{{ status('failed', row.lastActivity.counts.failed + ' failed') }}{% else %}0{% endif %}</td>
205
199
  {% else %}
206
- <td><span class="admin-empty">Nothing recorded.</span></td>
200
+ <td>Nothing recorded.</td>
207
201
  <td>—</td>
208
202
  <td>—</td>
209
203
  <td>—</td>
210
204
  {% endif %}
211
205
  <td>
212
206
  {% if row.webmentions.sent or row.webmentions["none"] or row.webmentions.failed %}
213
- {{ row.webmentions.sent }} told{% if row.webmentions["none"] %}, {{ row.webmentions["none"] }} take none{% endif %}{% if row.webmentions.failed %}, <span class="admin-status admin-status-failed">{{ row.webmentions.failed }} failed</span>{% endif %}
207
+ {{ row.webmentions.sent }} told{% if row.webmentions["none"] %}, {{ row.webmentions["none"] }} take none{% endif %}{% if row.webmentions.failed %}, {{ status('failed', row.webmentions.failed + ' failed') }}{% endif %}
214
208
  {% else %}
215
- <span class="admin-empty">—</span>
209
+ —
216
210
  {% endif %}
217
211
  {% if row.syndication.length %}
218
- <ul class="admin-syndication">
212
+ <ul>
219
213
  {% for target in row.syndication %}
220
- <li>{{ target.name }}: {% if target.status == "failed" %}<span class="admin-status admin-status-failed">failed</span>{% if target.error %} ({{ target.error }}){% endif %}{% elif target.status == "none" %}takes none{% elif target.status %}sent{% else %}not sent yet{% endif %}{% if target.copy %}, <a href="{{ target.copy }}">copy</a>{% endif %}</li>
214
+ <li>{{ target.name }}: {% if target.status == "failed" %}{{ status('failed', 'failed') }}{% if target.error %} ({{ target.error }}){% endif %}{% elif target.status == "none" %}takes none{% elif target.status %}sent{% else %}not sent yet{% endif %}{% if target.copy %}, <a class="link" href="{{ target.copy }}">copy</a>{% endif %}</li>
221
215
  {% endfor %}
222
216
  </ul>
223
217
  {% endif %}
224
218
  </td>
225
- <td class="admin-actions">
219
+ <td>
226
220
  <form method="post" action="{{ resendUrl }}">
227
221
  <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
228
222
  <input type="hidden" name="{{ fields.slug }}" value="{{ row.slug }}" />
229
- <button type="submit">Resend</button>
223
+ {{ button('Resend', type='submit', style='ghost', size='xs') }}
230
224
  </form>
231
225
  </td>
232
226
  </tr>
233
227
  {% endfor %}
234
228
  </tbody>
235
- </table>
236
- <p class="admin-hint">
229
+ {% endcall %}
230
+ <p class="mt-4 max-w-prose text-sm">
237
231
  Resending builds the post again from its file and sends it to every one
238
232
  of its author's followers and every accepted relay the site has now, and tells every
239
233
  page the post links to at the same time: an update for a
@@ -242,7 +236,7 @@
242
236
  recorded against them.
243
237
  </p>
244
238
  {% else %}
245
- <p class="admin-empty">No post has been announced to the fediverse yet.</p>
239
+ <p>No post has been announced to the fediverse yet.</p>
246
240
  {% endif %}
247
241
  </section>
248
242
  {% endblock %}
@@ -6,6 +6,8 @@
6
6
  a user's profile now (decision-14). #}
7
7
  {% extends "layouts/settings-page.njk" %}
8
8
  {% import "components/fields.njk" as field %}
9
+ {% from "components/card.njk" import card %}
10
+ {% from "components/table.njk" import table %}
9
11
 
10
12
  {% block settingsProblems %}
11
13
  {{ field.problem('settings-relays', problems.relays) }}
@@ -22,7 +24,7 @@
22
24
  {{ field.textarea('settings-relays', fields.relays, 'Relays', form.relays,
23
25
  error=problems.relays, hint=relaysHint, rows='3', spellcheck='false', autofocus=true) }}
24
26
 
25
- <h2>WordPress</h2>
27
+ <h2 class="mt-6 text-lg font-semibold">WordPress</h2>
26
28
 
27
29
  {% set wordpressHint %}
28
30
  Answer the inbox and collection paths the WordPress ActivityPub plugin
@@ -41,12 +43,9 @@
41
43
  {# When each compatibility path was last asked for. It is the whole reason
42
44
  the instants are recorded: once every follower's server has refetched the
43
45
  actor, nothing asks any more and the switch can go off. #}
44
- <section class="admin-settings admin-wordpress-panel">
45
- <h2>WordPress paths</h2>
46
-
46
+ {% call card(title='WordPress paths') %}
47
47
  {% if wordpressRoutes.length %}
48
- <table class="admin-table">
49
- <caption class="admin-visually-hidden">WordPress paths</caption>
48
+ {% call table('WordPress paths', inCard=true) %}
50
49
  <thead>
51
50
  <tr><th scope="col">Path</th><th scope="col">For</th><th scope="col">Last asked for</th></tr>
52
51
  </thead>
@@ -55,7 +54,7 @@
55
54
  <tr>
56
55
  <td><code>{{ route.path }}</code></td>
57
56
  <td>{{ route.username or 'every user' }}</td>
58
- <td>
57
+ <td class="whitespace-nowrap">
59
58
  {% if route.lastRequestedAt %}
60
59
  {{ route.lastRequestedAt | date('readable') }}
61
60
  {% else %}
@@ -65,18 +64,18 @@
65
64
  </tr>
66
65
  {% endfor %}
67
66
  </tbody>
68
- </table>
69
- <p class="admin-hint">
67
+ {% endcall %}
68
+ <p class="text-sm">
70
69
  Once every one of these has been quiet for long enough that every
71
70
  follower's server has refetched the actor, turn the switch off: these
72
71
  paths are a cache other servers hold, not this site's identity, and the
73
72
  CMS carries them only until the caches have moved on.
74
73
  </p>
75
74
  {% else %}
76
- <p class="admin-hint">
75
+ <p class="text-sm">
77
76
  No user carries a WordPress actor id, so the switch would serve nothing.
78
77
  The <code>geekity import wordpress-actor</code> command sets one.
79
78
  </p>
80
79
  {% endif %}
81
- </section>
80
+ {% endcall %}
82
81
  {% endblock %}
@@ -1,55 +1,71 @@
1
1
  {# The IndieAuth consent screen (TASK-158): an app wants to know who the
2
- signed-in person is. A bare page like the login form, because the person
3
- arrived from another site and has one thing to decide here. #}
2
+ signed-in person is. One card in the bare column, like the login form,
3
+ because the person arrived from another site and has one thing to decide
4
+ here. #}
4
5
  {% extends "layouts/base.njk" %}
5
6
  {% import "components/fields.njk" as field %}
7
+ {% from "components/alert.njk" import alert %}
8
+ {% from "components/button.njk" import button %}
9
+ {% from "components/card.njk" import card, cardActions %}
6
10
 
7
11
  {% block title %}Sign in to {{ client.name }}{% endblock %}
8
12
 
9
13
  {% block content %}
10
- {# A data: URI the server fetched, never the client's URL (TASK-190). #}
11
- {% if client.logo %}
12
- <img class="admin-consent-logo" src="{{ client.logo }}" alt="" width="64" height="64" />
13
- {% endif %}
14
- <h1>Sign in to {{ client.name }}?</h1>
15
-
16
- <dl class="admin-consent">
17
- <dt>App</dt>
18
- <dd>{{ client.name }}{% if client.named %} <span class="admin-hint">({{ client.id }})</span>{% endif %}</dd>
19
- <dt>Sends you back to</dt>
20
- <dd>{{ redirectHost }}</dd>
21
- <dt>Signs you in as</dt>
22
- <dd>{{ identity }}</dd>
23
- {% if resource %}
24
- <dt>For use at</dt>
25
- <dd>{{ resource }}</dd>
14
+ {% call card() %}
15
+ {# A data: URI the server fetched, never the client's URL (TASK-190). #}
16
+ {% if client.logo %}
17
+ <div class="avatar">
18
+ <div class="w-16 rounded-box">
19
+ <img class="object-cover" src="{{ client.logo }}" alt="" width="64" height="64" />
20
+ </div>
21
+ </div>
26
22
  {% endif %}
27
- </dl>
28
-
29
- {% if withoutPkce %}
30
- <p class="admin-hint">This app does not use PKCE, which protects a sign-in if the code it is handed is intercepted. It is let in only because it is on your list of apps allowed without PKCE, under Users &gt; Connected apps.</p>
31
- {% endif %}
32
-
33
- {% if loopback %}
34
- <p class="admin-hint">This app runs on your own computer or network. Approve only if you started this sign-in yourself.</p>
35
- {% endif %}
36
-
37
- <form method="post" action="{{ consentUrl }}">
38
- <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
39
- <input type="hidden" name="request" value="{{ pending }}" />
40
-
41
- {% if scopes | length %}
42
- <fieldset>
43
- <legend>It also asks for</legend>
44
- {% for scope in scopes %}
45
- {{ field.checkbox('scope-' ~ scope.name, 'scope', scope.label, checked=true, value=scope.name) }}
46
- {% endfor %}
47
- </fieldset>
48
- {% else %}
49
- <p>It asks only who you are.</p>
23
+ <h1 class="card-title text-2xl break-all">Sign in to {{ client.name }}?</h1>
24
+
25
+ <dl class="grid grid-cols-[auto_1fr] gap-x-4 gap-y-1">
26
+ <dt class="font-semibold">App</dt>
27
+ <dd class="break-all">{{ client.name }}{% if client.named %} <span class="text-sm">({{ client.id }})</span>{% endif %}</dd>
28
+ <dt class="font-semibold">Sends you back to</dt>
29
+ <dd class="break-all">{{ redirectHost }}</dd>
30
+ <dt class="font-semibold">Signs you in as</dt>
31
+ <dd class="break-all">{{ identity }}</dd>
32
+ {% if resource %}
33
+ <dt class="font-semibold">For use at</dt>
34
+ <dd class="break-all">{{ resource }}</dd>
35
+ {% endif %}
36
+ </dl>
37
+
38
+ {% if withoutPkce %}
39
+ {% call alert(color='warning', style='soft') %}
40
+ <p>This app does not use PKCE, which protects a sign-in if the code it is handed is intercepted. It is let in only because it is on your list of apps allowed without PKCE, under Users &gt; Connected apps.</p>
41
+ {% endcall %}
42
+ {% endif %}
43
+
44
+ {% if loopback %}
45
+ {% call alert(color='info', style='soft', polite=true) %}
46
+ <p>This app runs on your own computer or network. Approve only if you started this sign-in yourself.</p>
47
+ {% endcall %}
50
48
  {% endif %}
51
49
 
52
- <button type="submit" name="decision" value="approve">Approve</button>
53
- <button type="submit" name="decision" value="deny">Deny</button>
54
- </form>
50
+ <form method="post" action="{{ consentUrl }}">
51
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
52
+ <input type="hidden" name="request" value="{{ pending }}" />
53
+
54
+ {% if scopes | length %}
55
+ <fieldset class="fieldset">
56
+ <legend class="fieldset-legend">It also asks for</legend>
57
+ {% for scope in scopes %}
58
+ {{ field.checkbox('scope-' ~ scope.name, 'scope', scope.label, checked=true, value=scope.name) }}
59
+ {% endfor %}
60
+ </fieldset>
61
+ {% else %}
62
+ <p>It asks only who you are.</p>
63
+ {% endif %}
64
+
65
+ {% call cardActions() %}
66
+ {{ button('Approve', type='submit', color='primary', name='decision', value='approve') }}
67
+ {{ button('Deny', type='submit', style='ghost', name='decision', value='deny') }}
68
+ {% endcall %}
69
+ </form>
70
+ {% endcall %}
55
71
  {% endblock %}
@@ -1,11 +1,14 @@
1
1
  {# A sign-in request that cannot go ahead (TASK-158). Shown rather than
2
2
  redirected, because the fault is in the address it would redirect to. #}
3
3
  {% extends "layouts/base.njk" %}
4
+ {% from "components/card.njk" import card %}
4
5
 
5
6
  {% block title %}Sign-in refused{% endblock %}
6
7
 
7
8
  {% block content %}
8
- <h1>This sign-in cannot go ahead</h1>
9
- <p>{{ message }}</p>
10
- <p>Go back to the app and try again. If it keeps happening, the app may be set up wrongly.</p>
9
+ {% call card() %}
10
+ <h1 class="card-title text-2xl">This sign-in cannot go ahead</h1>
11
+ <p>{{ message }}</p>
12
+ <p>Go back to the app and try again. If it keeps happening, the app may be set up wrongly.</p>
13
+ {% endcall %}
11
14
  {% endblock %}