@geekity/cms 0.9.0 → 0.11.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.
- package/README.md +86 -24
- package/admin/components/admin-bar.njk +26 -0
- package/admin/components/fields.njk +55 -12
- package/admin/components/public-admin-bar.njk +41 -0
- package/admin/layouts/base.njk +6 -1
- package/admin/layouts/settings-page.njk +7 -2
- package/admin/layouts/shell.njk +9 -20
- package/admin/pages/account/forgot.njk +1 -1
- package/admin/pages/account/login.njk +1 -1
- package/admin/pages/account/reset.njk +4 -2
- package/admin/pages/account/setup.njk +1 -1
- package/admin/pages/dashboard/home.njk +1 -0
- package/admin/pages/documents/list.njk +1 -0
- package/admin/pages/documents/taxonomy.njk +1 -0
- package/admin/pages/federation/followers.njk +3 -0
- package/admin/pages/federation/settings.njk +5 -0
- package/admin/pages/media/library.njk +39 -0
- package/admin/pages/navigation/menus.njk +6 -1
- package/admin/pages/settings/discussion.njk +7 -0
- package/admin/pages/settings/email.njk +10 -0
- package/admin/pages/settings/general.njk +7 -0
- package/admin/pages/settings/permalinks.njk +6 -0
- package/admin/pages/settings/reading.njk +7 -0
- package/admin/pages/tools/content-index.njk +1 -0
- package/admin/pages/tools/personal-data.njk +5 -0
- package/admin/pages/users/edit.njk +7 -5
- package/admin/pages/users/list.njk +1 -0
- package/admin/pages/users/new.njk +5 -1
- package/admin/static/admin-bar.css +153 -0
- package/admin/static/admin.css +95 -96
- package/dist/admin/comments.js +2 -1
- package/dist/admin/comments.js.map +1 -1
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +18 -0
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/index.d.ts +1 -1
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/media.d.ts +13 -2
- package/dist/admin/media.d.ts.map +1 -1
- package/dist/admin/media.js +58 -3
- package/dist/admin/media.js.map +1 -1
- package/dist/admin/personal-data.d.ts.map +1 -1
- package/dist/admin/personal-data.js +5 -1
- package/dist/admin/personal-data.js.map +1 -1
- package/dist/admin/preview.d.ts.map +1 -1
- package/dist/admin/preview.js +1 -1
- package/dist/admin/preview.js.map +1 -1
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +2 -1
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/store.d.ts +36 -1
- package/dist/admin/store.d.ts.map +1 -1
- package/dist/admin/store.js +63 -1
- package/dist/admin/store.js.map +1 -1
- package/dist/admin/templates.d.ts +1 -0
- package/dist/admin/templates.d.ts.map +1 -1
- package/dist/admin/templates.js +1 -0
- package/dist/admin/templates.js.map +1 -1
- package/dist/admin/tools.d.ts +2 -0
- package/dist/admin/tools.d.ts.map +1 -1
- package/dist/admin/tools.js +3 -2
- package/dist/admin/tools.js.map +1 -1
- package/dist/admin/uploads.d.ts +5 -2
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +6 -2
- package/dist/admin/uploads.js.map +1 -1
- package/dist/comments/index.d.ts +2 -2
- package/dist/comments/index.d.ts.map +1 -1
- package/dist/comments/index.js +1 -1
- package/dist/comments/index.js.map +1 -1
- package/dist/comments/records.d.ts +43 -2
- package/dist/comments/records.d.ts.map +1 -1
- package/dist/comments/records.js +201 -54
- package/dist/comments/records.js.map +1 -1
- package/dist/comments/routes.js +1 -1
- package/dist/comments/routes.js.map +1 -1
- package/dist/comments/viewer.d.ts +13 -0
- package/dist/comments/viewer.d.ts.map +1 -1
- package/dist/comments/viewer.js +13 -1
- package/dist/comments/viewer.js.map +1 -1
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/env.d.ts +19 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +37 -1
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/delivery.d.ts +3 -1
- package/dist/federation/delivery.d.ts.map +1 -1
- package/dist/federation/delivery.js +6 -1
- package/dist/federation/delivery.js.map +1 -1
- package/dist/federation/federation.d.ts +3 -0
- package/dist/federation/federation.d.ts.map +1 -1
- package/dist/federation/federation.js.map +1 -1
- package/dist/federation/inbox.d.ts +7 -5
- package/dist/federation/inbox.d.ts.map +1 -1
- package/dist/federation/inbox.js +15 -32
- package/dist/federation/inbox.js.map +1 -1
- package/dist/federation/index.d.ts +2 -0
- package/dist/federation/index.d.ts.map +1 -1
- package/dist/federation/index.js +1 -0
- package/dist/federation/index.js.map +1 -1
- package/dist/federation/mount.js +6 -1
- package/dist/federation/mount.js.map +1 -1
- package/dist/federation/profiles.d.ts +95 -0
- package/dist/federation/profiles.d.ts.map +1 -0
- package/dist/federation/profiles.js +171 -0
- package/dist/federation/profiles.js.map +1 -0
- package/dist/federation/relays.d.ts +3 -1
- package/dist/federation/relays.d.ts.map +1 -1
- package/dist/federation/relays.js +6 -1
- package/dist/federation/relays.js.map +1 -1
- package/dist/federation/replies.d.ts +13 -4
- package/dist/federation/replies.d.ts.map +1 -1
- package/dist/federation/replies.js +25 -6
- package/dist/federation/replies.js.map +1 -1
- package/dist/images/alt-text.d.ts +51 -0
- package/dist/images/alt-text.d.ts.map +1 -0
- package/dist/images/alt-text.js +113 -0
- package/dist/images/alt-text.js.map +1 -0
- package/dist/images/icons.d.ts.map +1 -1
- package/dist/images/icons.js +3 -2
- package/dist/images/icons.js.map +1 -1
- package/dist/images/index.d.ts +2 -2
- package/dist/images/index.d.ts.map +1 -1
- package/dist/images/markup.d.ts +26 -4
- package/dist/images/markup.d.ts.map +1 -1
- package/dist/images/markup.js +36 -15
- package/dist/images/markup.js.map +1 -1
- package/dist/images/paths.d.ts +11 -0
- package/dist/images/paths.d.ts.map +1 -1
- package/dist/images/paths.js +17 -1
- package/dist/images/paths.js.map +1 -1
- package/dist/images/variants.d.ts +13 -3
- package/dist/images/variants.d.ts.map +1 -1
- package/dist/images/variants.js +13 -11
- package/dist/images/variants.js.map +1 -1
- package/dist/index.d.ts +11 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +50 -11
- package/dist/index.js.map +1 -1
- package/dist/notifications/routes.js +1 -1
- package/dist/notifications/routes.js.map +1 -1
- package/dist/privacy/erase.d.ts.map +1 -1
- package/dist/privacy/erase.js +2 -3
- package/dist/privacy/erase.js.map +1 -1
- package/dist/privacy/retention.js +1 -1
- package/dist/privacy/retention.js.map +1 -1
- package/dist/web/admin-bar.d.ts +21 -0
- package/dist/web/admin-bar.d.ts.map +1 -0
- package/dist/web/admin-bar.js +145 -0
- package/dist/web/admin-bar.js.map +1 -0
- package/dist/web/assets.d.ts +29 -1
- package/dist/web/assets.d.ts.map +1 -1
- package/dist/web/assets.js +48 -3
- package/dist/web/assets.js.map +1 -1
- package/dist/web/compression.d.ts +19 -0
- package/dist/web/compression.d.ts.map +1 -0
- package/dist/web/compression.js +160 -0
- package/dist/web/compression.js.map +1 -0
- package/dist/web/context.d.ts +5 -1
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +5 -2
- package/dist/web/context.js.map +1 -1
- package/dist/web/conversation.d.ts.map +1 -1
- package/dist/web/conversation.js +13 -12
- package/dist/web/conversation.js.map +1 -1
- package/dist/web/render.d.ts +27 -0
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +77 -38
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +63 -28
- package/dist/web/routes.js.map +1 -1
- package/dist/web/templates.d.ts.map +1 -1
- package/dist/web/templates.js +9 -2
- package/dist/web/templates.js.map +1 -1
- package/dist/webmention/service.d.ts.map +1 -1
- package/dist/webmention/service.js +5 -1
- package/dist/webmention/service.js.map +1 -1
- package/package.json +8 -8
- package/themes/default/README.md +176 -19
- package/themes/default/layouts/base.njk +51 -10
- package/themes/default/layouts/post.njk +10 -1
- package/themes/default/partials/comment-form.njk +33 -14
- package/themes/default/partials/contact-form.njk +32 -14
- package/themes/default/static/style.css +109 -24
|
@@ -60,9 +60,11 @@
|
|
|
60
60
|
<p class="admin-empty">Nothing has been uploaded yet.</p>
|
|
61
61
|
{% else %}
|
|
62
62
|
<table class="admin-list admin-media">
|
|
63
|
+
<caption class="admin-visually-hidden">{{ heading }}</caption>
|
|
63
64
|
<thead>
|
|
64
65
|
<tr>
|
|
65
66
|
<th scope="col">File</th>
|
|
67
|
+
<th scope="col">Alt text</th>
|
|
66
68
|
<th scope="col">Uploaded</th>
|
|
67
69
|
<th scope="col">Size</th>
|
|
68
70
|
<th scope="col">Link</th>
|
|
@@ -83,6 +85,43 @@
|
|
|
83
85
|
{% endif %}
|
|
84
86
|
<a href="{{ file.url }}">{{ file.path }}</a>
|
|
85
87
|
</td>
|
|
88
|
+
<td class="admin-media-alt">
|
|
89
|
+
{% if file.image %}
|
|
90
|
+
<form method="post" action="{{ altUrl }}">
|
|
91
|
+
<input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
|
|
92
|
+
<input type="hidden" name="{{ fields.path }}" value="{{ file.path }}" />
|
|
93
|
+
<input type="hidden" name="{{ fields.page }}" value="{{ page }}" />
|
|
94
|
+
<label class="admin-visually-hidden" for="media-alt-{{ loop.index }}">
|
|
95
|
+
Alt text for {{ file.name }}
|
|
96
|
+
</label>
|
|
97
|
+
<input
|
|
98
|
+
id="media-alt-{{ loop.index }}"
|
|
99
|
+
name="{{ fields.alt }}"
|
|
100
|
+
type="text"
|
|
101
|
+
value="{% if file.alt and file.alt.kind == 'described' %}{{ file.alt.text }}{% endif %}"
|
|
102
|
+
aria-describedby="media-alt-state-{{ loop.index }}"
|
|
103
|
+
/>
|
|
104
|
+
<span class="admin-check">
|
|
105
|
+
<input
|
|
106
|
+
id="media-decorative-{{ loop.index }}"
|
|
107
|
+
name="{{ fields.decorative }}"
|
|
108
|
+
type="checkbox"
|
|
109
|
+
value="1"
|
|
110
|
+
{% if file.alt and file.alt.kind == 'decorative' %}checked{% endif %}
|
|
111
|
+
/>
|
|
112
|
+
<label for="media-decorative-{{ loop.index }}">Decorative</label>
|
|
113
|
+
</span>
|
|
114
|
+
<button type="submit">Save</button>
|
|
115
|
+
<span id="media-alt-state-{{ loop.index }}" class="admin-status{% if not file.alt %} admin-status-missing{% endif %}">
|
|
116
|
+
{%- if not file.alt %}Missing: describe it, or mark it decorative
|
|
117
|
+
{%- elif file.alt.kind == 'decorative' %}Decorative: inserted with an empty alt
|
|
118
|
+
{%- else %}Offered when it is inserted{% endif -%}
|
|
119
|
+
</span>
|
|
120
|
+
</form>
|
|
121
|
+
{% else %}
|
|
122
|
+
<span class="admin-status">Not an image</span>
|
|
123
|
+
{% endif %}
|
|
124
|
+
</td>
|
|
86
125
|
<td>{{ file.modified | date('html') }}</td>
|
|
87
126
|
<td>{{ file.bytes }}</td>
|
|
88
127
|
<td class="admin-media-links">
|
|
@@ -60,7 +60,12 @@
|
|
|
60
60
|
<h1>{{ heading }}</h1>
|
|
61
61
|
|
|
62
62
|
{% if hasProblems %}
|
|
63
|
-
|
|
63
|
+
{% call field.summary('Nothing was saved. Fix the box marked below and try again.') %}
|
|
64
|
+
{% for menu in areas.concat(others) %}
|
|
65
|
+
{{ field.problem('menu-' + menu.name, menu.problem) }}
|
|
66
|
+
{% endfor %}
|
|
67
|
+
{{ field.problem('menu-name', nameProblem) }}
|
|
68
|
+
{% endcall %}
|
|
64
69
|
{% endif %}
|
|
65
70
|
|
|
66
71
|
<h2>Where {{ themeName }} puts a menu</h2>
|
|
@@ -13,6 +13,13 @@
|
|
|
13
13
|
{%- endif -%}
|
|
14
14
|
{% endmacro %}
|
|
15
15
|
|
|
16
|
+
{% block settingsProblems %}
|
|
17
|
+
{{ field.problem('settings-comments-close', problems.commentsCloseAfterDays) }}
|
|
18
|
+
{{ field.problem('settings-comment-email-retention', problems.commentEmailRetentionDays) }}
|
|
19
|
+
{{ field.problem('settings-address-hash-retention', problems.addressHashRetentionDays) }}
|
|
20
|
+
{{ field.problem('settings-contact-message-retention', problems.contactMessageRetentionDays) }}
|
|
21
|
+
{% endblock %}
|
|
22
|
+
|
|
16
23
|
{% block settingsFields %}
|
|
17
24
|
<h2>Comments</h2>
|
|
18
25
|
|
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
{% extends "layouts/settings-page.njk" %}
|
|
4
4
|
{% import "components/fields.njk" as field %}
|
|
5
5
|
|
|
6
|
+
{% block settingsProblems %}
|
|
7
|
+
{{ field.problem('settings-mail-provider', problems.mailProvider) }}
|
|
8
|
+
{{ field.problem('settings-mail-from-address', problems.mailFromAddress) }}
|
|
9
|
+
{{ field.problem('settings-mail-reply-to', problems.mailReplyTo) }}
|
|
10
|
+
{{ field.problem('settings-contact-email', problems.contactEmail) }}
|
|
11
|
+
{{ field.problem('settings-security-contacts', problems.securityContacts) }}
|
|
12
|
+
{{ field.problem('settings-security-policy', problems.securityPolicy) }}
|
|
13
|
+
{{ field.problem('settings-security-languages', problems.securityLanguages) }}
|
|
14
|
+
{% endblock %}
|
|
15
|
+
|
|
6
16
|
{% block settingsFields %}
|
|
7
17
|
{% set providerHint %}
|
|
8
18
|
The key or password each one needs is a credential and is saved below,
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
{% extends "layouts/settings-page.njk" %}
|
|
3
3
|
{% import "components/fields.njk" as field %}
|
|
4
4
|
|
|
5
|
+
{% block settingsProblems %}
|
|
6
|
+
{{ field.problem('settings-title', problems.title) }}
|
|
7
|
+
{{ field.problem('settings-base-url', problems.baseUrl) }}
|
|
8
|
+
{{ field.problem('settings-timezone', problems.timezone) }}
|
|
9
|
+
{{ field.problem('settings-language', problems.language) }}
|
|
10
|
+
{% endblock %}
|
|
11
|
+
|
|
5
12
|
{% block settingsFields %}
|
|
6
13
|
{{ field.text('settings-title', fields.title, 'Title', form.title,
|
|
7
14
|
error=problems.title, required=true, autofocus=true) }}
|
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
{% extends "layouts/settings-page.njk" %}
|
|
4
4
|
{% import "components/fields.njk" as field %}
|
|
5
5
|
|
|
6
|
+
{% block settingsProblems %}
|
|
7
|
+
{{ field.problem('settings-tag-base', problems.tagBase) }}
|
|
8
|
+
{{ field.problem('settings-category-base', problems.categoryBase) }}
|
|
9
|
+
{% endblock %}
|
|
10
|
+
|
|
6
11
|
{% block settingsFields %}
|
|
7
12
|
{% set tagBaseHint %}The tag archives live at <code>/{{ form.tagBase }}/{tag}/</code>. One path segment, no slashes.{% endset %}
|
|
8
13
|
{{ field.text('settings-tag-base', fields.tagBase, 'Tag base', form.tagBase,
|
|
@@ -22,6 +27,7 @@
|
|
|
22
27
|
|
|
23
28
|
{% if taxonomyRedirects.length %}
|
|
24
29
|
<table class="admin-list">
|
|
30
|
+
<caption class="admin-visually-hidden">Archive redirects</caption>
|
|
25
31
|
<thead>
|
|
26
32
|
<tr><th scope="col">Taxonomy</th><th scope="col">Was</th><th scope="col">Is now</th></tr>
|
|
27
33
|
</thead>
|
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
{% extends "layouts/settings-page.njk" %}
|
|
5
5
|
{% import "components/fields.njk" as field %}
|
|
6
6
|
|
|
7
|
+
{% block settingsProblems %}
|
|
8
|
+
{{ field.problem('settings-homepage', problems.homepage) }}
|
|
9
|
+
{{ field.problem('settings-posts-page', problems.postsPage) }}
|
|
10
|
+
{{ field.problem('settings-posts-per-page', problems.postsPerPage) }}
|
|
11
|
+
{{ field.problem('settings-notify-server', problems.notifyServer) }}
|
|
12
|
+
{% endblock %}
|
|
13
|
+
|
|
7
14
|
{% block settingsFields %}
|
|
8
15
|
{# WordPress's "Your homepage displays": the empty option is Your latest
|
|
9
16
|
posts, so the choice and the page it needs are one control rather than a
|
|
@@ -49,6 +49,11 @@
|
|
|
49
49
|
{% endif %}
|
|
50
50
|
</form>
|
|
51
51
|
{% else %}
|
|
52
|
+
{% if problem %}
|
|
53
|
+
{% call field.summary('Nothing was looked up.') %}
|
|
54
|
+
{{ field.problem('personal-data-email', problem) }}
|
|
55
|
+
{% endcall %}
|
|
56
|
+
{% endif %}
|
|
52
57
|
<form class="admin-settings" method="post" action="{{ actionUrl }}">
|
|
53
58
|
<input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
|
|
54
59
|
{{ field.text('personal-data-email', fields.email, 'Email address', email,
|
|
@@ -80,10 +80,9 @@
|
|
|
80
80
|
</p>
|
|
81
81
|
|
|
82
82
|
{% if profileProblems.links %}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
</p>
|
|
83
|
+
{% call field.summary('Nothing was saved. Fix the Links box below and save again; every other box here still holds what you typed.') %}
|
|
84
|
+
{{ field.problem('profile-links', profileProblems.links) }}
|
|
85
|
+
{% endcall %}
|
|
87
86
|
{% endif %}
|
|
88
87
|
|
|
89
88
|
{{ field.text('profile-display-name', fields.displayName, 'Display name',
|
|
@@ -219,7 +218,10 @@
|
|
|
219
218
|
<h2>Change your password</h2>
|
|
220
219
|
|
|
221
220
|
{% if passwordProblems.currentPassword or passwordProblems.newPassword %}
|
|
222
|
-
|
|
221
|
+
{% call field.summary('Your password was not changed. Fix the fields marked below and try again.') %}
|
|
222
|
+
{{ field.problem('current-password', passwordProblems.currentPassword) }}
|
|
223
|
+
{{ field.problem('new-password', passwordProblems.newPassword) }}
|
|
224
|
+
{% endcall %}
|
|
223
225
|
{% endif %}
|
|
224
226
|
|
|
225
227
|
{{ field.password('current-password', fields.currentPassword, 'Current password',
|
|
@@ -16,7 +16,11 @@
|
|
|
16
16
|
<input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
|
|
17
17
|
|
|
18
18
|
{% if addProblems.username or addProblems.password or addProblems.email %}
|
|
19
|
-
|
|
19
|
+
{% call field.summary('Nobody was added. Fix the fields marked below and try again.') %}
|
|
20
|
+
{{ field.problem('add-username', addProblems.username) }}
|
|
21
|
+
{{ field.problem('add-email', addProblems.email) }}
|
|
22
|
+
{{ field.problem('add-password', addProblems.password) }}
|
|
23
|
+
{% endcall %}
|
|
20
24
|
{% endif %}
|
|
21
25
|
|
|
22
26
|
{{ field.text('add-username', fields.username, 'Username', addForm.username,
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The admin bar: the dark strip across the top of every admin screen, and of
|
|
3
|
+
* every public page a signed-in user reads (TASK-183).
|
|
4
|
+
*
|
|
5
|
+
* Self-contained, because on the public site it is inlined into the bar's
|
|
6
|
+
* shadow root, under a host reset to `all: initial`: nothing here may lean on
|
|
7
|
+
* admin.css or on whatever theme the site wears. Sizes are in pixels for the
|
|
8
|
+
* same reason, since a `rem` is the theme's root font size. The colours are
|
|
9
|
+
* declared on `:host` there and on `:root` in the admin, where admin.css
|
|
10
|
+
* reads them too.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
:root,
|
|
14
|
+
:host {
|
|
15
|
+
--admin-bar: #1d2327;
|
|
16
|
+
--admin-nav: #2c3338;
|
|
17
|
+
--admin-nav-text: #f0f0f1;
|
|
18
|
+
--admin-focus-on-dark: #fff;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.admin-bar,
|
|
22
|
+
.admin-bar * {
|
|
23
|
+
box-sizing: border-box;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Site name on the left, the shortcuts beside it, who you are on the right. */
|
|
27
|
+
|
|
28
|
+
.admin-bar {
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-wrap: wrap;
|
|
31
|
+
align-items: center;
|
|
32
|
+
gap: 0 16px;
|
|
33
|
+
padding: 0 16px;
|
|
34
|
+
min-height: 40px;
|
|
35
|
+
background: var(--admin-bar);
|
|
36
|
+
color: var(--admin-nav-text);
|
|
37
|
+
font:
|
|
38
|
+
14px/40px -apple-system,
|
|
39
|
+
BlinkMacSystemFont,
|
|
40
|
+
'Segoe UI',
|
|
41
|
+
Roboto,
|
|
42
|
+
sans-serif;
|
|
43
|
+
anchor-name: --admin-bar;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.admin-bar a {
|
|
47
|
+
color: var(--admin-nav-text);
|
|
48
|
+
text-decoration: none;
|
|
49
|
+
white-space: nowrap;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.admin-bar a:hover,
|
|
53
|
+
.admin-bar a:focus {
|
|
54
|
+
color: #72aee6;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* The ring where the keyboard is, white on the dark bar. Here rather than in
|
|
58
|
+
admin.css because on the public site this is the only stylesheet the bar
|
|
59
|
+
has. */
|
|
60
|
+
|
|
61
|
+
.admin-bar :focus-visible {
|
|
62
|
+
outline: 2px solid var(--admin-focus-on-dark);
|
|
63
|
+
outline-offset: 2px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.admin-bar-site {
|
|
67
|
+
font-weight: 600;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.admin-bar-spacer {
|
|
71
|
+
flex: 1;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.admin-bar-account {
|
|
75
|
+
padding: 0;
|
|
76
|
+
border: 0;
|
|
77
|
+
background: none;
|
|
78
|
+
color: var(--admin-nav-text);
|
|
79
|
+
font: inherit;
|
|
80
|
+
text-align: right;
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
anchor-name: --admin-account;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* On a phone the bar wraps, and the greeting keeps to the right of its line
|
|
86
|
+
so the menu under it opens inside the screen. */
|
|
87
|
+
|
|
88
|
+
.admin-bar-spacer + .admin-bar-account {
|
|
89
|
+
margin-left: auto;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.admin-bar-account:hover,
|
|
93
|
+
.admin-bar-account:focus-visible,
|
|
94
|
+
.admin-bar-account:popover-open {
|
|
95
|
+
color: #72aee6;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.admin-bar-account::after {
|
|
99
|
+
content: ' \25BE' / '';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* The menu is in the top layer, so it is placed rather than laid out: under
|
|
103
|
+
the greeting where anchor positioning exists, at the bar's right edge
|
|
104
|
+
where it does not. */
|
|
105
|
+
|
|
106
|
+
.admin-account-menu {
|
|
107
|
+
inset: 40px 0 auto auto;
|
|
108
|
+
margin: 0;
|
|
109
|
+
min-width: 160px;
|
|
110
|
+
padding: 4px 0;
|
|
111
|
+
border: 0;
|
|
112
|
+
background: var(--admin-nav);
|
|
113
|
+
color: var(--admin-nav-text);
|
|
114
|
+
line-height: 1.6;
|
|
115
|
+
box-shadow: 0 3px 5px rgb(0 0 0 / 20%);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@supports (top: anchor(--admin-bar bottom)) {
|
|
119
|
+
.admin-account-menu {
|
|
120
|
+
inset: anchor(--admin-bar bottom) anchor(--admin-account right) auto auto;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.admin-account-menu a,
|
|
125
|
+
.admin-account-menu button[type='submit'] {
|
|
126
|
+
display: block;
|
|
127
|
+
box-sizing: border-box;
|
|
128
|
+
width: 100%;
|
|
129
|
+
margin: 0;
|
|
130
|
+
padding: 8px 16px;
|
|
131
|
+
border: 0;
|
|
132
|
+
border-radius: 0;
|
|
133
|
+
background: none;
|
|
134
|
+
color: var(--admin-nav-text);
|
|
135
|
+
font: inherit;
|
|
136
|
+
text-align: left;
|
|
137
|
+
text-decoration: none;
|
|
138
|
+
cursor: pointer;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* A menu entry fills the menu's width, so its ring is drawn inside it. */
|
|
142
|
+
|
|
143
|
+
.admin-bar .admin-account-menu :focus-visible {
|
|
144
|
+
outline-offset: -2px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.admin-account-menu a:hover,
|
|
148
|
+
.admin-account-menu a:focus-visible,
|
|
149
|
+
.admin-account-menu button[type='submit']:hover,
|
|
150
|
+
.admin-account-menu button[type='submit']:focus-visible {
|
|
151
|
+
background: var(--admin-bar);
|
|
152
|
+
color: #72aee6;
|
|
153
|
+
}
|
package/admin/static/admin.css
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
:root {
|
|
11
|
-
--admin-bar
|
|
12
|
-
--admin-nav: #2c3338;
|
|
13
|
-
--admin-nav-text: #f0f0f1;
|
|
11
|
+
/* --admin-bar, --admin-nav and --admin-nav-text are in admin-bar.css. */
|
|
14
12
|
--admin-nav-current: #2271b1;
|
|
13
|
+
--admin-nav-open: #1d2327;
|
|
14
|
+
--admin-nav-children: #32373c;
|
|
15
15
|
--admin-field: #f0f0f1;
|
|
16
16
|
--admin-surface: #fff;
|
|
17
17
|
--admin-border: #c3c4c7;
|
|
@@ -20,7 +20,12 @@
|
|
|
20
20
|
--admin-link: #2271b1;
|
|
21
21
|
--admin-notice: #00a32a;
|
|
22
22
|
--admin-error: #d63638;
|
|
23
|
+
--admin-warning: #dba617;
|
|
23
24
|
--admin-unread: #f0f6fc;
|
|
25
|
+
/* The focus ring on the light field and surfaces; --admin-focus-on-dark,
|
|
26
|
+
for the bar and the menu column, is in admin-bar.css. Both are held to 3:1
|
|
27
|
+
against what they are drawn on by src/admin/keyboard.test.ts. */
|
|
28
|
+
--admin-focus: #2271b1;
|
|
24
29
|
--admin-nav-width: 11rem;
|
|
25
30
|
}
|
|
26
31
|
|
|
@@ -44,103 +49,33 @@ a {
|
|
|
44
49
|
color: var(--admin-link);
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
/*
|
|
52
|
+
/* Every control says where the keyboard is, in one colour that holds 3:1
|
|
53
|
+
against the field and the surfaces, rather than the browser's own ring,
|
|
54
|
+
which is faint on grey. Set off by 2px so it is drawn on the background
|
|
55
|
+
around the control, whatever colour the control itself is. */
|
|
48
56
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
gap: 1rem;
|
|
53
|
-
padding: 0 1rem;
|
|
54
|
-
min-height: 2.5rem;
|
|
55
|
-
background: var(--admin-bar);
|
|
56
|
-
color: var(--admin-nav-text);
|
|
57
|
-
anchor-name: --admin-bar;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.admin-bar a {
|
|
61
|
-
color: var(--admin-nav-text);
|
|
62
|
-
text-decoration: none;
|
|
63
|
-
white-space: nowrap;
|
|
57
|
+
:focus-visible {
|
|
58
|
+
outline: 2px solid var(--admin-focus);
|
|
59
|
+
outline-offset: 2px;
|
|
64
60
|
}
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
.admin-bar a:focus {
|
|
68
|
-
color: #72aee6;
|
|
69
|
-
}
|
|
62
|
+
/* Hidden until a keyboard reaches it, then drawn over the bar. */
|
|
70
63
|
|
|
71
|
-
.admin-
|
|
64
|
+
.admin-skip-link {
|
|
65
|
+
position: absolute;
|
|
66
|
+
top: 0;
|
|
67
|
+
left: 0;
|
|
68
|
+
z-index: 1;
|
|
69
|
+
padding: 0.6rem 0.9rem;
|
|
70
|
+
background: var(--admin-surface);
|
|
71
|
+
color: var(--admin-link);
|
|
72
72
|
font-weight: 600;
|
|
73
|
+
transform: translateY(-120%);
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
.admin-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
.admin-bar-account {
|
|
80
|
-
padding: 0;
|
|
81
|
-
border: 0;
|
|
82
|
-
background: none;
|
|
83
|
-
color: var(--admin-nav-text);
|
|
84
|
-
font: inherit;
|
|
85
|
-
text-align: right;
|
|
86
|
-
cursor: pointer;
|
|
87
|
-
anchor-name: --admin-account;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.admin-bar-account:hover,
|
|
91
|
-
.admin-bar-account:focus-visible,
|
|
92
|
-
.admin-bar-account:popover-open {
|
|
93
|
-
color: #72aee6;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.admin-bar-account::after {
|
|
97
|
-
content: ' \25BE' / '';
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/* The menu is in the top layer, so it is placed rather than laid out: under
|
|
101
|
-
the greeting where anchor positioning exists, at the bar's right edge
|
|
102
|
-
where it does not. */
|
|
103
|
-
|
|
104
|
-
.admin-account-menu {
|
|
105
|
-
inset: 2.5rem 0 auto auto;
|
|
106
|
-
margin: 0;
|
|
107
|
-
min-width: 10rem;
|
|
108
|
-
padding: 0.25rem 0;
|
|
109
|
-
border: 0;
|
|
110
|
-
background: var(--admin-nav);
|
|
111
|
-
color: var(--admin-nav-text);
|
|
112
|
-
box-shadow: 0 3px 5px rgb(0 0 0 / 20%);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
@supports (top: anchor(--admin-bar bottom)) {
|
|
116
|
-
.admin-account-menu {
|
|
117
|
-
inset: anchor(--admin-bar bottom) anchor(--admin-account right) auto auto;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
.admin-account-menu a,
|
|
122
|
-
.admin-account-menu button[type='submit'] {
|
|
123
|
-
display: block;
|
|
124
|
-
box-sizing: border-box;
|
|
125
|
-
width: 100%;
|
|
126
|
-
margin: 0;
|
|
127
|
-
padding: 0.5rem 1rem;
|
|
128
|
-
border: 0;
|
|
129
|
-
border-radius: 0;
|
|
130
|
-
background: none;
|
|
131
|
-
color: var(--admin-nav-text);
|
|
132
|
-
font: inherit;
|
|
133
|
-
text-align: left;
|
|
134
|
-
text-decoration: none;
|
|
135
|
-
cursor: pointer;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
.admin-account-menu a:hover,
|
|
139
|
-
.admin-account-menu a:focus-visible,
|
|
140
|
-
.admin-account-menu button[type='submit']:hover,
|
|
141
|
-
.admin-account-menu button[type='submit']:focus-visible {
|
|
142
|
-
background: var(--admin-bar);
|
|
143
|
-
color: #72aee6;
|
|
76
|
+
.admin-skip-link:focus {
|
|
77
|
+
transform: none;
|
|
78
|
+
outline-offset: -4px;
|
|
144
79
|
}
|
|
145
80
|
|
|
146
81
|
/* The shell: navigation column beside the screen itself. */
|
|
@@ -170,11 +105,18 @@ a {
|
|
|
170
105
|
}
|
|
171
106
|
|
|
172
107
|
.admin-nav a:hover,
|
|
173
|
-
.admin-nav a:focus {
|
|
108
|
+
.admin-nav a:focus-visible {
|
|
174
109
|
background: var(--admin-bar);
|
|
175
110
|
color: #72aee6;
|
|
176
111
|
}
|
|
177
112
|
|
|
113
|
+
/* Each entry fills the column, so its ring is drawn inside it. */
|
|
114
|
+
|
|
115
|
+
.admin-nav a:focus-visible {
|
|
116
|
+
outline-color: var(--admin-focus-on-dark);
|
|
117
|
+
outline-offset: -2px;
|
|
118
|
+
}
|
|
119
|
+
|
|
178
120
|
.admin-nav a[aria-current='page'] {
|
|
179
121
|
background: var(--admin-nav-current);
|
|
180
122
|
color: #fff;
|
|
@@ -193,12 +135,12 @@ a {
|
|
|
193
135
|
}
|
|
194
136
|
|
|
195
137
|
.admin-nav-open > .admin-nav-heading {
|
|
196
|
-
background:
|
|
138
|
+
background: var(--admin-nav-open);
|
|
197
139
|
color: #fff;
|
|
198
140
|
}
|
|
199
141
|
|
|
200
142
|
.admin-nav-children {
|
|
201
|
-
background:
|
|
143
|
+
background: var(--admin-nav-children);
|
|
202
144
|
font-size: 0.95em;
|
|
203
145
|
}
|
|
204
146
|
|
|
@@ -283,6 +225,12 @@ h2 {
|
|
|
283
225
|
border-left-color: var(--admin-error);
|
|
284
226
|
}
|
|
285
227
|
|
|
228
|
+
/* Done, but with something still to fix: a post published with an image
|
|
229
|
+
nobody has described. */
|
|
230
|
+
.admin-flash-warning {
|
|
231
|
+
border-left-color: var(--admin-warning);
|
|
232
|
+
}
|
|
233
|
+
|
|
286
234
|
/* Panels, the box every group of things on the dashboard sits in. */
|
|
287
235
|
|
|
288
236
|
.admin-panels {
|
|
@@ -336,6 +284,12 @@ h2 {
|
|
|
336
284
|
border-collapse: collapse;
|
|
337
285
|
}
|
|
338
286
|
|
|
287
|
+
.admin-list caption:not(.admin-visually-hidden) {
|
|
288
|
+
padding: 0.4rem 0;
|
|
289
|
+
text-align: left;
|
|
290
|
+
font-weight: 600;
|
|
291
|
+
}
|
|
292
|
+
|
|
339
293
|
.admin-list th {
|
|
340
294
|
text-align: left;
|
|
341
295
|
color: var(--admin-muted);
|
|
@@ -430,6 +384,25 @@ button[type='submit']:hover,
|
|
|
430
384
|
border-left: 4px solid var(--admin-error);
|
|
431
385
|
}
|
|
432
386
|
|
|
387
|
+
/* A refused form's summary: what went wrong as its heading, and a link to
|
|
388
|
+
each field to put right. It takes focus on load, so the outline says
|
|
389
|
+
where the keyboard now is. */
|
|
390
|
+
|
|
391
|
+
.admin-error-summary h2 {
|
|
392
|
+
margin: 0;
|
|
393
|
+
font-size: 1em;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.admin-error-summary ul {
|
|
397
|
+
margin: 0.4rem 0 0;
|
|
398
|
+
padding-left: 1.25rem;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.admin-error-summary:focus {
|
|
402
|
+
outline: 2px solid var(--admin-error);
|
|
403
|
+
outline-offset: 2px;
|
|
404
|
+
}
|
|
405
|
+
|
|
433
406
|
.admin-note {
|
|
434
407
|
color: var(--admin-muted);
|
|
435
408
|
}
|
|
@@ -994,6 +967,32 @@ button[type='submit']:hover,
|
|
|
994
967
|
min-width: 18rem;
|
|
995
968
|
}
|
|
996
969
|
|
|
970
|
+
/* An image's alt text, edited in its row. The state underneath says what
|
|
971
|
+
inserting it will do, and a missing one reads as a problem. */
|
|
972
|
+
|
|
973
|
+
.admin-media-alt {
|
|
974
|
+
min-width: 16rem;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
.admin-media-alt form {
|
|
978
|
+
display: flex;
|
|
979
|
+
flex-wrap: wrap;
|
|
980
|
+
align-items: center;
|
|
981
|
+
gap: 0.3rem 0.6rem;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
.admin-media-alt input[type='text'] {
|
|
985
|
+
flex: 1 1 100%;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
.admin-media-alt .admin-status {
|
|
989
|
+
flex: 1 1 100%;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
.admin-status-missing {
|
|
993
|
+
color: var(--admin-error);
|
|
994
|
+
}
|
|
995
|
+
|
|
997
996
|
/* The copy control: a readonly field that works on its own, and a button that
|
|
998
997
|
copy.js reveals. The field is monospaced because what is in it is a URL or a
|
|
999
998
|
line of Markdown, and both are read character by character. */
|
package/dist/admin/comments.js
CHANGED
|
@@ -208,7 +208,8 @@ function removedNote(redacted) {
|
|
|
208
208
|
}
|
|
209
209
|
/** The files and the index this request writes through. */
|
|
210
210
|
function recordsOf(c) {
|
|
211
|
-
|
|
211
|
+
const { contentDir, dataDir } = c.var.config;
|
|
212
|
+
return { admin: c.var.admin, contentDir, dataDir };
|
|
212
213
|
}
|
|
213
214
|
/** One stored comment as the screen shows it. */
|
|
214
215
|
function commentRow(c, comment) {
|