@geekity/cms 0.21.0 → 0.22.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 (99) hide show
  1. package/README.md +23 -0
  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 +155 -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/documents.js +1 -1
  77. package/dist/admin/documents.js.map +1 -1
  78. package/dist/admin/headers.js +1 -1
  79. package/dist/admin/headers.js.map +1 -1
  80. package/dist/admin/routes.d.ts.map +1 -1
  81. package/dist/admin/routes.js +17 -8
  82. package/dist/admin/routes.js.map +1 -1
  83. package/dist/admin/templates.d.ts +6 -3
  84. package/dist/admin/templates.d.ts.map +1 -1
  85. package/dist/admin/templates.js +25 -3
  86. package/dist/admin/templates.js.map +1 -1
  87. package/dist/admin/users.d.ts +4 -0
  88. package/dist/admin/users.d.ts.map +1 -1
  89. package/dist/admin/users.js +37 -1
  90. package/dist/admin/users.js.map +1 -1
  91. package/dist/content/post-type.d.ts.map +1 -1
  92. package/dist/content/post-type.js +7 -2
  93. package/dist/content/post-type.js.map +1 -1
  94. package/dist/web/admin-bar.d.ts +4 -4
  95. package/dist/web/admin-bar.d.ts.map +1 -1
  96. package/dist/web/admin-bar.js +11 -34
  97. package/dist/web/admin-bar.js.map +1 -1
  98. package/package.json +8 -4
  99. package/themes/default/README.md +3 -1
@@ -1,112 +1,103 @@
1
1
  {# The listing behind /admin/posts and /admin/pages. One template for both:
2
2
  `kind` says which, and whether the table has a date column and taxonomy
3
- ones.
4
-
5
- There is no `pages/posts/` or `pages/categories/` for the same reason.
6
- Posts, Pages, Categories and Tags are four menu entries over three
7
- templates — this listing, the editor beside it and the taxonomy screen —
8
- because a post and a page differ by a `kind`, not by a screen. A folder per
9
- menu entry would mean either a second copy of each template or a re-export
10
- that exists only to make the directory look like the menu, so the folder is
11
- named after what the screens are about instead. #}
3
+ ones. `pages/documents/` is named after what its screens are about rather
4
+ than after the menu, because Posts, Pages, Categories and Tags are four
5
+ menu entries over three templates. #}
12
6
  {% extends "layouts/shell.njk" %}
7
+ {% from "components/badge.njk" import status %}
8
+ {% from "components/button.njk" import button, buttonLink %}
9
+ {% from "components/pagination.njk" import pagination %}
10
+ {% from "components/table.njk" import table, row, heading, cell, rowToggle %}
11
+ {% from "components/tabs.njk" import tabs %}
13
12
 
14
13
  {% block title %}{{ kind.plural }}{% endblock %}
15
14
 
16
15
  {% block content %}
17
- <h1>{{ kind.plural }} <a class="admin-button admin-button-small" href="{{ newUrl }}">Add new</a></h1>
16
+ <div class="mb-6 flex flex-wrap items-center gap-4">
17
+ <h1 class="text-2xl font-bold">{{ kind.plural }}</h1>
18
+ {{ buttonLink('Add new', newUrl, color='primary') }}
19
+ </div>
18
20
 
19
- <ul class="admin-filters">
20
- {% for entry in filters %}
21
- <li>
22
- <a href="{{ entry.url }}"{% if entry.current %} aria-current="true"{% endif %}>{{ entry.label }}</a>
23
- </li>
24
- {% endfor %}
25
- </ul>
21
+ <div class="mb-4 max-w-full overflow-x-auto contain-inline-size">
22
+ {{ tabs(filters, 'Show ' + (kind.plural | lower)) }}
23
+ </div>
26
24
 
27
25
  {% if documents.length %}
28
- <table class="admin-list">
29
- <caption class="admin-visually-hidden">{{ kind.plural }}</caption>
26
+ {% call table(kind.plural) %}
30
27
  <thead>
31
28
  <tr>
32
29
  <th scope="col">Title</th>
33
- <th scope="col">Author</th>
30
+ {{ heading('Author') }}
34
31
  {% if kind.tagged %}
35
- <th scope="col">Tags</th>
32
+ {{ heading('Tags') }}
36
33
  {% endif %}
37
34
  {% if kind.categorised %}
38
- <th scope="col">Categories</th>
35
+ {{ heading('Categories') }}
39
36
  {% endif %}
40
37
  {% if kind.dated %}
41
- <th scope="col">Date</th>
38
+ {{ heading('Date') }}
42
39
  {% else %}
43
- <th scope="col">Updated</th>
40
+ {{ heading('Updated') }}
44
41
  {% endif %}
45
- <th scope="col">Status</th>
46
- <th scope="col">Actions</th>
42
+ {{ heading('Status') }}
47
43
  </tr>
48
44
  </thead>
49
45
  <tbody>
50
46
  {% for document in documents %}
51
- <tr>
52
- <td><a href="{{ document.editUrl }}">{{ document.title }}</a>{% if document.role %} &mdash; <span class="admin-page-role">{{ document.role }}</span>{% endif %}</td>
53
- <td>{{ document.author }}</td>
47
+ {% call row() %}
48
+ <td>
49
+ <a class="link link-hover font-medium" href="{{ document.editUrl }}">{{ document.title }}</a>{% if document.role %} &mdash; {{ document.role }}{% endif %}
50
+ <div class="-ms-2 mt-1 flex items-center gap-1 whitespace-nowrap transition-opacity lg:[@media(hover:hover)]:opacity-0 group-hover:opacity-100 group-focus-within:opacity-100">
51
+ {{ buttonLink('Edit', document.editUrl, style='ghost', size='xs') }}
52
+ <form method="post" action="{{ document.editUrl }}">
53
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
54
+ <input type="hidden" name="return" value="{{ returnUrl }}" />
55
+ {% if document.trashed %}
56
+ {{ button('Restore', type='submit', name='action', value='restore', style='ghost', size='xs') }}
57
+ {% else %}
58
+ {{ button('Move to trash', type='submit', name='action', value='trash', style='ghost', size='xs') }}
59
+ {% endif %}
60
+ </form>
61
+ {% if document.viewUrl %}
62
+ {{ buttonLink('View', document.viewUrl, style='ghost', size='xs') }}
63
+ {% endif %}
64
+ </div>
65
+ {{ rowToggle(document.title) }}
66
+ </td>
67
+ {% call cell('Author', nowrap=true) %}{{ document.author }}{% endcall %}
54
68
  {% if kind.tagged %}
55
- <td>{{ document.tags }}</td>
69
+ {% call cell('Tags') %}{{ document.tags }}{% endcall %}
56
70
  {% endif %}
57
71
  {% if kind.categorised %}
58
- <td>{{ document.categories }}</td>
72
+ {% call cell('Categories') %}{{ document.categories }}{% endcall %}
59
73
  {% endif %}
60
74
  {% if kind.dated %}
61
- <td>{{ document.date | date('html') }}</td>
75
+ {% call cell('Date', nowrap=true) %}{{ document.date | date('html') }}{% endcall %}
62
76
  {% else %}
63
- <td>{{ document.updated | date('html') }}</td>
77
+ {% call cell('Updated', nowrap=true) %}{{ document.updated | date('html') }}{% endcall %}
64
78
  {% endif %}
65
- <td>
79
+ {% call cell('Status') %}
66
80
  {% if document.trashed %}
67
- <span class="admin-status admin-status-trashed">Trash</span>
81
+ {{ status('trashed', 'Trash') }}
68
82
  {% elif document.draft %}
69
- <span class="admin-status admin-status-draft">Draft</span>
83
+ {{ status('draft', 'Draft') }}
70
84
  {% elif document.scheduled %}
71
- <span class="admin-status admin-status-scheduled">Scheduled</span>
85
+ {{ status('scheduled', 'Scheduled') }}
72
86
  {% elif document.hidden %}
73
- <span class="admin-status admin-status-draft">Hidden</span>
87
+ {{ status('hidden', 'Hidden') }}
74
88
  {% else %}
75
- <span class="admin-status">Published</span>
89
+ {{ status('published', 'Published') }}
76
90
  {% endif %}
77
- </td>
78
- <td class="admin-actions">
79
- <a href="{{ document.editUrl }}">Edit</a>
80
- <form method="post" action="{{ document.editUrl }}">
81
- <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
82
- <input type="hidden" name="return" value="{{ returnUrl }}" />
83
- {% if document.trashed %}
84
- <button type="submit" name="action" value="restore">Restore</button>
85
- {% else %}
86
- <button type="submit" name="action" value="trash">Move to trash</button>
87
- {% endif %}
88
- </form>
89
- {% if document.viewUrl %}
90
- <a href="{{ document.viewUrl }}">View</a>
91
- {% endif %}
92
- </td>
93
- </tr>
91
+ {% endcall %}
92
+ {% endcall %}
94
93
  {% endfor %}
95
94
  </tbody>
96
- </table>
95
+ {% endcall %}
97
96
 
98
- {% if previousUrl or nextUrl %}
99
- <nav class="admin-pagination" aria-label="Pages">
100
- {% if previousUrl %}
101
- <a rel="prev" href="{{ previousUrl }}">Newer</a>
102
- {% endif %}
103
- <span>Page {{ page }}</span>
104
- {% if nextUrl %}
105
- <a rel="next" href="{{ nextUrl }}">Older</a>
106
- {% endif %}
107
- </nav>
108
- {% endif %}
97
+ <div class="mt-4">
98
+ {{ pagination(page, previousUrl=previousUrl, nextUrl=nextUrl) }}
99
+ </div>
109
100
  {% else %}
110
- <p class="admin-empty">Nothing here.</p>
101
+ <p>Nothing here.</p>
111
102
  {% endif %}
112
103
  {% endblock %}
@@ -1,13 +1,19 @@
1
1
  {# /admin/syndication: the services a post can be sent to, which is
2
2
  content/_data/syndicationTargets.json itself.
3
3
 
4
- One panel per entry the file holds, in file order, the broken ones too:
5
- an entry that declares nothing says why, so it can be fixed or removed here.
6
- Each panel saves or removes its own entry, and the Add form at the bottom
7
- appends one. A file that is not a JSON list is shown with its problem and
8
- no forms, because saving over it would lose what it holds. #}
4
+ A table of every entry the file holds, in file order, the broken ones too,
5
+ each marked offered or ignored; then one card per entry that saves or
6
+ removes it, and the Add card that appends one. An entry that declares
7
+ nothing says why, so it can be fixed or removed here. A file that is not a
8
+ JSON list is shown with its problem and no forms, because saving over it
9
+ would lose what it holds. #}
9
10
  {% extends "layouts/shell.njk" %}
10
11
  {% import "components/fields.njk" as field %}
12
+ {% from "components/alert.njk" import alert %}
13
+ {% from "components/badge.njk" import status %}
14
+ {% from "components/button.njk" import button %}
15
+ {% from "components/card.njk" import card, cardActions %}
16
+ {% from "components/table.njk" import table %}
11
17
 
12
18
  {% block title %}{{ heading }}{% endblock %}
13
19
 
@@ -30,23 +36,25 @@
30
36
  {% endmacro %}
31
37
 
32
38
  {% block content %}
33
- <h1>{{ heading }}</h1>
39
+ <h1 class="mb-6 text-2xl font-bold">{{ heading }}</h1>
34
40
 
35
41
  {% if hasProblems %}
36
- {% call field.summary('Nothing was saved. Fix the fields marked below and try again.') %}
37
- {% for panel in panels.concat([adding]) %}
38
- {% if panel.key == refusedKey %}
39
- {{ field.problem(panel.key + '-id', panel.problems.id) }}
40
- {{ field.problem(panel.key + '-name', panel.problems.name) }}
41
- {{ field.problem(panel.key + '-url', panel.problems.url) }}
42
- {{ field.problem(panel.key + '-tag', panel.problems.tag) }}
43
- {{ field.problem(panel.key + '-languages', panel.problems.languages) }}
44
- {% endif %}
45
- {% endfor %}
46
- {% endcall %}
42
+ <div class="max-w-2xl">
43
+ {% call field.summary('Nothing was saved. Fix the fields marked below and try again.') %}
44
+ {% for panel in panels.concat([adding]) %}
45
+ {% if panel.key == refusedKey %}
46
+ {{ field.problem(panel.key + '-id', panel.problems.id) }}
47
+ {{ field.problem(panel.key + '-name', panel.problems.name) }}
48
+ {{ field.problem(panel.key + '-url', panel.problems.url) }}
49
+ {{ field.problem(panel.key + '-tag', panel.problems.tag) }}
50
+ {{ field.problem(panel.key + '-languages', panel.problems.languages) }}
51
+ {% endif %}
52
+ {% endfor %}
53
+ {% endcall %}
54
+ </div>
47
55
  {% endif %}
48
56
 
49
- <p class="admin-hint">
57
+ <p class="mb-6 max-w-prose text-sm">
50
58
  Services such as IndieNews and Bridgy Publish copy a post when it links to them and sends
51
59
  them a webmention. Each target listed here gets a checkbox in the post editor and is offered
52
60
  to Micropub clients. They are kept in <code>content/{{ file }}</code>, which this screen reads
@@ -54,57 +62,87 @@
54
62
  </p>
55
63
 
56
64
  {% if fileProblem %}
57
- <div class="admin-error" role="alert">
58
- <p>{{ fileProblem }} No target is offered until it is fixed. Fix or remove the file by hand;
59
- this screen will not save over it, because that would lose what it holds.</p>
65
+ <div class="max-w-2xl">
66
+ {% call alert(color='error') %}
67
+ <p>{{ fileProblem }} No target is offered until it is fixed. Fix or remove the file by hand;
68
+ this screen will not save over it, because that would lose what it holds.</p>
69
+ {% endcall %}
60
70
  </div>
61
71
  {% else %}
62
- <h2>Targets</h2>
63
-
64
72
  {% if panels.length %}
65
- <ul class="admin-menu-boxes">
73
+ <div class="mb-8">
74
+ {% call table('Targets') %}
75
+ <thead>
76
+ <tr>
77
+ <th scope="col">Name</th>
78
+ <th scope="col">Id</th>
79
+ <th scope="col">URL</th>
80
+ <th scope="col">Status</th>
81
+ </tr>
82
+ </thead>
83
+ <tbody>
84
+ {% for panel in panels %}
85
+ <tr>
86
+ <td><a class="link link-hover font-medium" href="#{{ panel.key }}">{{ panel.form.name or ('Entry ' + (panel.index + 1)) }}</a></td>
87
+ <td><code>{{ panel.form.id }}</code></td>
88
+ <td class="break-all">{{ panel.form.url }}</td>
89
+ <td>
90
+ {% if panel.fileProblems.length %}
91
+ {{ status('failed', 'Ignored') }}
92
+ {% else %}
93
+ {{ status('accepted', 'Offered') }}
94
+ {% endif %}
95
+ </td>
96
+ </tr>
97
+ {% endfor %}
98
+ </tbody>
99
+ {% endcall %}
100
+ </div>
101
+
102
+ <div class="grid max-w-2xl grid-cols-1 gap-6">
66
103
  {% for panel in panels %}
67
- <li class="admin-menu-box">
68
- <h3>{{ panel.form.name or ('Entry ' + (panel.index + 1)) }}</h3>
69
- {% if panel.fileProblems.length %}
70
- {% for problem in panel.fileProblems %}
71
- <p class="admin-field-error">This entry is ignored. {{ problem }}</p>
72
- {% endfor %}
73
- {% else %}
74
- <p class="admin-menu-name"><code>{{ panel.form.id }}</code></p>
75
- {% endif %}
104
+ <div id="{{ panel.key }}">
105
+ {% call card(title=(panel.form.name or ('Entry ' + (panel.index + 1)))) %}
106
+ {% if panel.fileProblems.length %}
107
+ {% for problem in panel.fileProblems %}
108
+ <p>This entry is ignored. {{ problem }}</p>
109
+ {% endfor %}
110
+ {% else %}
111
+ <p><code>{{ panel.form.id }}</code></p>
112
+ {% endif %}
76
113
 
77
- <form method="post" action="{{ saveUrl }}">
78
- <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
79
- <input type="hidden" name="{{ fields.entry }}" value="{{ panel.index }}" />
80
- <input type="hidden" name="{{ fields.was }}" value="{{ panel.was }}" />
81
- {{ boxes(panel, fields) }}
82
- <p class="admin-menu-buttons">
83
- <button type="submit">Save target</button>
84
- </p>
85
- </form>
114
+ <form method="post" action="{{ saveUrl }}">
115
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
116
+ <input type="hidden" name="{{ fields.entry }}" value="{{ panel.index }}" />
117
+ <input type="hidden" name="{{ fields.was }}" value="{{ panel.was }}" />
118
+ {{ boxes(panel, fields) }}
119
+ <div class="mt-4">{{ button('Save target', type='submit', color='primary') }}</div>
120
+ </form>
86
121
 
87
- <form class="admin-menu-delete" method="post" action="{{ deleteUrl }}">
88
- <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
89
- <input type="hidden" name="{{ fields.entry }}" value="{{ panel.index }}" />
90
- <input type="hidden" name="{{ fields.was }}" value="{{ panel.was }}" />
91
- <button type="submit">Remove this target</button>
92
- </form>
93
- </li>
122
+ <form method="post" action="{{ deleteUrl }}">
123
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
124
+ <input type="hidden" name="{{ fields.entry }}" value="{{ panel.index }}" />
125
+ <input type="hidden" name="{{ fields.was }}" value="{{ panel.was }}" />
126
+ {% call cardActions() %}
127
+ {{ button('Remove this target', type='submit', color='error', style='ghost') }}
128
+ {% endcall %}
129
+ </form>
130
+ {% endcall %}
131
+ </div>
94
132
  {% endfor %}
95
- </ul>
133
+ </div>
96
134
  {% else %}
97
- <p class="admin-hint">This site declares no targets, so the editor offers none.</p>
135
+ <p class="mb-8">This site declares no targets, so the editor offers none.</p>
98
136
  {% endif %}
99
137
 
100
- <h2>Add a target</h2>
101
-
102
- <form class="admin-menu-add" method="post" action="{{ addUrl }}">
103
- <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
104
- {{ boxes(adding, fields) }}
105
- <p class="admin-menu-buttons">
106
- <button type="submit">Add target</button>
107
- </p>
108
- </form>
138
+ <div class="mt-8 max-w-2xl">
139
+ {% call card(title='Add a target') %}
140
+ <form method="post" action="{{ addUrl }}">
141
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
142
+ {{ boxes(adding, fields) }}
143
+ <div class="mt-4">{{ button('Add target', type='submit', color='primary') }}</div>
144
+ </form>
145
+ {% endcall %}
146
+ </div>
109
147
  {% endif %}
110
148
  {% endblock %}
@@ -1,48 +1,51 @@
1
1
  {# /admin/tags and /admin/categories: every term in use, what carries it, and
2
- the three things that can be done to it — rename, merge and delete. One
2
+ the three things that can be done to it: rename, merge and delete. One
3
3
  template for both taxonomies; `kind` says which. #}
4
4
  {% extends "layouts/shell.njk" %}
5
+ {% from "components/alert.njk" import alert %}
6
+ {% from "components/button.njk" import button, buttonLink %}
7
+ {% from "components/card.njk" import card, cardActions %}
8
+ {% from "components/table.njk" import table %}
5
9
 
6
10
  {% block title %}{{ heading }}{% endblock %}
7
11
 
8
12
  {% block content %}
9
- <h1>{{ heading }}</h1>
13
+ <h1 class="mb-6 text-2xl font-bold">{{ heading }}</h1>
10
14
 
11
15
  {# Above the table rather than under the field it came from: a refusal may be
12
16
  about a term the table no longer has a row for. #}
13
17
  {% if problems.to %}
14
- <p class="admin-error">{{ problems.to }}</p>
18
+ <div class="mb-6 max-w-2xl">
19
+ {% call alert(color='error') %}<span id="taxonomy-problem">{{ problems.to }}</span>{% endcall %}
20
+ </div>
15
21
  {% endif %}
16
22
 
17
23
  {% if confirm %}
18
- <form class="admin-settings" method="post" action="{{ renameUrl }}">
24
+ <form class="mb-6 max-w-2xl" method="post" action="{{ renameUrl }}">
19
25
  <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
20
26
  <input type="hidden" name="{{ fields.term }}" value="{{ confirm.term }}" />
21
27
  <input type="hidden" name="{{ fields.to }}" value="{{ confirm.to }}" />
22
28
  <input type="hidden" name="{{ fields.confirm }}" value="1" />
23
-
24
- <h2>Merge “{{ confirm.term }}” into “{{ confirm.to }}”?</h2>
25
-
26
- <p>
27
- There is already a {{ label }} called “{{ confirm.to }}”, on
28
- {{ confirm.targetFiles }} {% if confirm.targetFiles == 1 %}file{% else %}files{% endif %}.
29
- Renaming “{{ confirm.term }}” merges the
30
- {{ confirm.files }} {% if confirm.files == 1 %}file{% else %}files{% endif %} carrying it
31
- into that one. A file that already carries both keeps it once.
32
- </p>
33
-
34
- <p class="admin-settings-buttons">
35
- <button type="submit">Merge them</button>
36
- <a href="{{ listUrl }}">Cancel</a>
37
- </p>
29
+ {% call card(title='Merge “' + confirm.term + '” into “' + confirm.to + '”?', style='border') %}
30
+ <p>
31
+ There is already a {{ label }} called “{{ confirm.to }}”, on
32
+ {{ confirm.targetFiles }} {% if confirm.targetFiles == 1 %}file{% else %}files{% endif %}.
33
+ Renaming “{{ confirm.term }}” merges the
34
+ {{ confirm.files }} {% if confirm.files == 1 %}file{% else %}files{% endif %} carrying it
35
+ into that one. A file that already carries both keeps it once.
36
+ </p>
37
+ {% call cardActions() %}
38
+ {{ buttonLink('Cancel', listUrl, style='ghost') }}
39
+ {{ button('Merge them', type='submit', color='primary') }}
40
+ {% endcall %}
41
+ {% endcall %}
38
42
  </form>
39
43
  {% endif %}
40
44
 
41
45
  {% if terms.length == 0 %}
42
46
  <p>Nothing carries a {{ label }} yet.</p>
43
47
  {% else %}
44
- <table class="admin-list">
45
- <caption class="admin-visually-hidden">{{ heading }}</caption>
48
+ {% call table(heading) %}
46
49
  <thead>
47
50
  <tr>
48
51
  <th scope="col">{{ kind.singular | capitalize }}</th>
@@ -54,42 +57,43 @@
54
57
  </thead>
55
58
  <tbody>
56
59
  {% for entry in terms %}
60
+ {% set refused = problems.to and form.term == entry.term %}
57
61
  <tr>
58
- <td><a href="{{ entry.archiveUrl }}">{{ entry.term }}</a></td>
62
+ <td><a class="link link-hover font-medium" href="{{ entry.archiveUrl }}">{{ entry.term }}</a></td>
59
63
  <td>{{ entry.published }}</td>
60
64
  <td>{{ entry.total }}</td>
61
65
  <td>
62
- <form class="admin-inline" method="post" action="{{ renameUrl }}">
66
+ <form class="flex items-center gap-2" method="post" action="{{ renameUrl }}">
63
67
  <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
64
68
  <input type="hidden" name="{{ fields.term }}" value="{{ entry.term }}" />
65
- <label class="admin-visually-hidden" for="rename-{{ loop.index }}">
66
- Rename {{ entry.term }} to
67
- </label>
69
+ <label class="sr-only" for="rename-{{ loop.index }}">Rename {{ entry.term }} to</label>
68
70
  <input
69
71
  id="rename-{{ loop.index }}"
70
72
  name="{{ fields.to }}"
71
73
  type="text"
72
74
  value="{% if form.term == entry.term %}{{ form.to }}{% endif %}"
73
75
  required
76
+ class="input input-sm w-40"
77
+ {% if refused %}aria-invalid="true" aria-describedby="taxonomy-problem"{% endif %}
74
78
  />
75
- <button type="submit">Rename</button>
79
+ {{ button('Rename', type='submit', size='sm') }}
76
80
  </form>
77
81
  </td>
78
- <td class="admin-actions">
82
+ <td>
79
83
  <form method="post" action="{{ deleteUrl }}">
80
84
  <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
81
85
  <input type="hidden" name="{{ fields.term }}" value="{{ entry.term }}" />
82
- <button type="submit">Delete</button>
86
+ {{ button('Delete', type='submit', style='ghost', size='xs') }}
83
87
  </form>
84
88
  </td>
85
89
  </tr>
86
90
  {% endfor %}
87
91
  </tbody>
88
- </table>
92
+ {% endcall %}
89
93
 
90
- <p class="admin-hint">
94
+ <p class="mt-4 max-w-prose text-sm">
91
95
  Renaming, merging and deleting rewrite the front matter of every file carrying the
92
- {{ label }} — drafts, scheduled posts and the trash included — and tell the feeds and the
96
+ {{ label }} (drafts, scheduled posts and the trash included) and tell the feeds and the
93
97
  fediverse about each published post that changed. The Files column is how many that is.
94
98
  </p>
95
99
  {% endif %}
@@ -1,11 +1,14 @@
1
+ {# The page an admin request that threw answers with. It extends the bare
2
+ layout rather than the shell because the shell reads the session, the menu
3
+ and the site, and any of those may be what failed. #}
1
4
  {% extends "layouts/base.njk" %}
5
+ {% from "components/card.njk" import card %}
2
6
 
3
7
  {% block title %}Something went wrong{% endblock %}
4
8
 
5
9
  {% block content %}
6
- {# The page an admin request that threw answers with. It extends the bare
7
- layout rather than the shell because the shell reads the session, the
8
- menu and the site, and any of those may be what failed. #}
9
- <h1>Something went wrong</h1>
10
- <p>This screen could not be shown because of a problem on the server. The error has been logged. Try again in a moment, or go back to the <a href="{{ adminUrl }}">dashboard</a>.</p>
10
+ {% call card() %}
11
+ <h1 class="card-title text-2xl">Something went wrong</h1>
12
+ <p>This screen could not be shown because of a problem on the server. The error has been logged. Try again in a moment, or go back to the <a class="link" href="{{ adminUrl }}">dashboard</a>.</p>
13
+ {% endcall %}
11
14
  {% endblock %}