@geekity/cms 0.15.0 → 0.16.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 +107 -0
- package/admin/pages/documents/editor.njk +51 -0
- package/admin/pages/documents/syndication.njk +110 -0
- package/admin/pages/federation/followers.njk +7 -0
- package/admin/static/admin.css +11 -0
- package/dist/admin/documents.d.ts +101 -0
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +199 -67
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/federation.d.ts +15 -0
- package/dist/admin/federation.d.ts.map +1 -1
- package/dist/admin/federation.js +19 -0
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/menu.d.ts.map +1 -1
- package/dist/admin/menu.js +3 -0
- package/dist/admin/menu.js.map +1 -1
- package/dist/admin/photo-field.d.ts +39 -0
- package/dist/admin/photo-field.d.ts.map +1 -0
- package/dist/admin/photo-field.js +91 -0
- package/dist/admin/photo-field.js.map +1 -0
- package/dist/admin/preview.d.ts.map +1 -1
- package/dist/admin/preview.js +6 -1
- package/dist/admin/preview.js.map +1 -1
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +4 -0
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/syndication-targets.d.ts +57 -0
- package/dist/admin/syndication-targets.d.ts.map +1 -0
- package/dist/admin/syndication-targets.js +266 -0
- package/dist/admin/syndication-targets.js.map +1 -0
- 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/uploads.d.ts +6 -0
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +1 -1
- package/dist/admin/uploads.js.map +1 -1
- package/dist/content/citation.d.ts +36 -0
- package/dist/content/citation.d.ts.map +1 -0
- package/dist/content/citation.js +31 -0
- package/dist/content/citation.js.map +1 -0
- package/dist/content/index.d.ts +2 -0
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +1 -0
- package/dist/content/index.js.map +1 -1
- package/dist/content/photo.d.ts +45 -0
- package/dist/content/photo.d.ts.map +1 -0
- package/dist/content/photo.js +55 -0
- package/dist/content/photo.js.map +1 -0
- package/dist/content/post-type.d.ts +20 -8
- package/dist/content/post-type.d.ts.map +1 -1
- package/dist/content/post-type.js +17 -0
- package/dist/content/post-type.js.map +1 -1
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +59 -5
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/citations.d.ts +38 -0
- package/dist/federation/citations.d.ts.map +1 -0
- package/dist/federation/citations.js +98 -0
- package/dist/federation/citations.js.map +1 -0
- package/dist/federation/delivery.d.ts.map +1 -1
- package/dist/federation/delivery.js +79 -31
- package/dist/federation/delivery.js.map +1 -1
- package/dist/images/alt-text.d.ts +6 -0
- package/dist/images/alt-text.d.ts.map +1 -1
- package/dist/images/alt-text.js +10 -0
- package/dist/images/alt-text.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -2
- package/dist/index.js.map +1 -1
- package/dist/indieauth/bearer.d.ts +6 -1
- package/dist/indieauth/bearer.d.ts.map +1 -1
- package/dist/indieauth/bearer.js +39 -12
- package/dist/indieauth/bearer.js.map +1 -1
- package/dist/indieauth/discovery.d.ts +9 -4
- package/dist/indieauth/discovery.d.ts.map +1 -1
- package/dist/indieauth/discovery.js +18 -7
- package/dist/indieauth/discovery.js.map +1 -1
- package/dist/micropub/create.d.ts +56 -0
- package/dist/micropub/create.d.ts.map +1 -0
- package/dist/micropub/create.js +200 -0
- package/dist/micropub/create.js.map +1 -0
- package/dist/micropub/endpoint.d.ts +21 -0
- package/dist/micropub/endpoint.d.ts.map +1 -0
- package/dist/micropub/endpoint.js +353 -0
- package/dist/micropub/endpoint.js.map +1 -0
- package/dist/micropub/media.d.ts +14 -0
- package/dist/micropub/media.d.ts.map +1 -0
- package/dist/micropub/media.js +93 -0
- package/dist/micropub/media.js.map +1 -0
- package/dist/micropub/update.d.ts +44 -0
- package/dist/micropub/update.d.ts.map +1 -0
- package/dist/micropub/update.js +133 -0
- package/dist/micropub/update.js.map +1 -0
- package/dist/web/context.d.ts +42 -3
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +41 -1
- package/dist/web/context.js.map +1 -1
- package/dist/web/render.d.ts +15 -0
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +16 -0
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.js +2 -2
- package/dist/webmention/index.d.ts +2 -0
- package/dist/webmention/index.d.ts.map +1 -1
- package/dist/webmention/index.js +1 -0
- package/dist/webmention/index.js.map +1 -1
- package/dist/webmention/service.d.ts.map +1 -1
- package/dist/webmention/service.js +96 -18
- package/dist/webmention/service.js.map +1 -1
- package/dist/webmention/syndication.d.ts +135 -0
- package/dist/webmention/syndication.d.ts.map +1 -0
- package/dist/webmention/syndication.js +337 -0
- package/dist/webmention/syndication.js.map +1 -0
- package/package.json +1 -1
- package/themes/default/README.md +40 -9
- package/themes/default/layouts/post.njk +19 -6
- package/themes/default/partials/citations.njk +17 -0
- package/themes/default/partials/jsonld.njk +12 -1
- package/themes/default/partials/photos.njk +10 -0
- package/themes/default/partials/post-list.njk +7 -0
- package/themes/default/src/style.css +9 -0
- package/themes/default/static/style.css +16 -0
package/README.md
CHANGED
|
@@ -1185,6 +1185,113 @@ answers 404 or 410 — takes it away. Closing rules do not apply: a post that
|
|
|
1185
1185
|
stopped taking comments still hears about a page that links to it, exactly as it
|
|
1186
1186
|
still hears a fediverse reply.
|
|
1187
1187
|
|
|
1188
|
+
### Syndication targets
|
|
1189
|
+
|
|
1190
|
+
Some services copy a post when it links to them and sends them a webmention,
|
|
1191
|
+
and answer with the address of the copy. IndieNews lists posts about the
|
|
1192
|
+
IndieWeb; Bridgy Publish posts to Mastodon, Bluesky, GitHub and Flickr. The
|
|
1193
|
+
CMS knows none of them by name. A site lists the ones it uses on the admin's
|
|
1194
|
+
**Posts > Syndication** screen (`/admin/syndication`), which reads
|
|
1195
|
+
and writes `content/_data/syndicationTargets.json`. The file stays the source of
|
|
1196
|
+
truth, so it can still be edited by hand, and it looks like this:
|
|
1197
|
+
|
|
1198
|
+
```json
|
|
1199
|
+
[
|
|
1200
|
+
{
|
|
1201
|
+
"id": "indienews",
|
|
1202
|
+
"name": "IndieNews",
|
|
1203
|
+
"url": "https://news.indieweb.org/en",
|
|
1204
|
+
"tag": "indienews"
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
"id": "mastodon",
|
|
1208
|
+
"name": "Mastodon",
|
|
1209
|
+
"url": "https://brid.gy/publish/mastodon"
|
|
1210
|
+
}
|
|
1211
|
+
]
|
|
1212
|
+
```
|
|
1213
|
+
|
|
1214
|
+
| Key | What it is |
|
|
1215
|
+
| ----------- | --------------------------------------------------------------------------------------------- |
|
|
1216
|
+
| `id` | What a post's `syndicate-to` lists. Letters, digits, `.`, `-` and `_`. |
|
|
1217
|
+
| `name` | What the editor's checkbox and the post's link say. |
|
|
1218
|
+
| `url` | The page the post links to and sends its webmention to. May hold `{lang}`. |
|
|
1219
|
+
| `tag` | Optional. A post carrying this tag is sent to the target without listing it. |
|
|
1220
|
+
| `languages` | Optional. The language tags the target takes posts in. A post in any other language skips it. |
|
|
1221
|
+
|
|
1222
|
+
An entry missing any of the first three, repeating an id, or with a `languages`
|
|
1223
|
+
value that is not a list of language tags, is ignored. It is reported in the log
|
|
1224
|
+
when the site starts, and the Syndication screen shows it with its problem so it
|
|
1225
|
+
can be fixed or removed there. No file means no targets.
|
|
1226
|
+
|
|
1227
|
+
The screen has a panel for each entry, in file order, and an **Add a target**
|
|
1228
|
+
form. A save is checked by the same rules the file is read by: a field that
|
|
1229
|
+
breaks one is marked on the form and the file is left as it was. A save that
|
|
1230
|
+
passes is written atomically, and the editor's **Syndicate to** checkboxes and
|
|
1231
|
+
Micropub's `q=syndicate-to` offer the change on the next request. A save or
|
|
1232
|
+
remove is refused when the entry changed in the file since the page was drawn.
|
|
1233
|
+
A file that is not a JSON list is shown with its problem and never saved over.
|
|
1234
|
+
To keep the default theme's old IndieNews link, add a target with the id
|
|
1235
|
+
`indienews`, the url `https://news.indieweb.org/{lang}` and the tag `indienews`.
|
|
1236
|
+
|
|
1237
|
+
Some targets have a page per language. IndieNews has `news.indieweb.org/en`,
|
|
1238
|
+
`/de`, `/fr` and more. Declare one target and put `{lang}` where the language
|
|
1239
|
+
goes:
|
|
1240
|
+
|
|
1241
|
+
```json
|
|
1242
|
+
{
|
|
1243
|
+
"id": "indienews",
|
|
1244
|
+
"name": "IndieNews",
|
|
1245
|
+
"url": "https://news.indieweb.org/{lang}",
|
|
1246
|
+
"tag": "indienews",
|
|
1247
|
+
"languages": ["en", "de", "fr"]
|
|
1248
|
+
}
|
|
1249
|
+
```
|
|
1250
|
+
|
|
1251
|
+
The CMS fills `{lang}` with the post's language: its `lang` front matter, or the
|
|
1252
|
+
site's language when the post names none. With `languages`, a post in a
|
|
1253
|
+
language the list does not name neither links to the target nor notifies it. A
|
|
1254
|
+
regional tag counts as its language, so a `de-AT` post goes to
|
|
1255
|
+
`news.indieweb.org/de`, and `{lang}` takes the tag from the list. Without
|
|
1256
|
+
`languages`, `{lang}` takes the post's own tag as written, region and all.
|
|
1257
|
+
|
|
1258
|
+
A post selects targets in one of two ways:
|
|
1259
|
+
|
|
1260
|
+
- **By listing them.** The post editor has a **Syndicate to** checkbox for each
|
|
1261
|
+
target, and saving writes the ticked ids into the front matter as
|
|
1262
|
+
`syndicate-to: [indienews, mastodon]`. An id no target declares is kept as
|
|
1263
|
+
written.
|
|
1264
|
+
- **By its tags.** A post tagged `indienews` is sent to the target whose `tag`
|
|
1265
|
+
is `indienews`, as the WordPress IndieNews plugin did.
|
|
1266
|
+
|
|
1267
|
+
The default theme links to each selected target at the start of the Published
|
|
1268
|
+
line, inside the post's `h-entry`, as `<a class="u-syndication"
|
|
1269
|
+
href="https://news.indieweb.org/en">IndieNews</a>`. That link is what IndieNews
|
|
1270
|
+
and Bridgy Publish check for when they fetch the post. When the post is
|
|
1271
|
+
published or updated, the sender adds each selected target to the pages it
|
|
1272
|
+
notifies, the same way it adds the post a reply answers. Nothing is sent while a
|
|
1273
|
+
page is served.
|
|
1274
|
+
|
|
1275
|
+
A target that answers `201` or `202` with a `Location` header has made a copy.
|
|
1276
|
+
The address is kept in `content/_data/syndication.json`, keyed by the post's
|
|
1277
|
+
permalink (decision-26), and the theme prints it after the dates as **Also on**
|
|
1278
|
+
with a `u-syndication` link. A copy made by hand goes in the post's own front
|
|
1279
|
+
matter, and is printed the same way:
|
|
1280
|
+
|
|
1281
|
+
```yaml
|
|
1282
|
+
syndication:
|
|
1283
|
+
- https://mastodon.social/@me/113000000000000000
|
|
1284
|
+
```
|
|
1285
|
+
|
|
1286
|
+
Removing a target from `syndicate-to`, or removing its tag, removes the link.
|
|
1287
|
+
The sender then tells the target, as it tells any page a post stops linking to,
|
|
1288
|
+
and the copy is dropped from `syndication.json`. IndieNews takes the post down
|
|
1289
|
+
when it finds the link gone. Drafting or trashing the post does the same.
|
|
1290
|
+
|
|
1291
|
+
The posts table on `/admin/federation` lists each selected target with how its
|
|
1292
|
+
last webmention went and a link to its copy, and **Resend** sends to the targets
|
|
1293
|
+
again.
|
|
1294
|
+
|
|
1188
1295
|
## Email
|
|
1189
1296
|
|
|
1190
1297
|
The CMS sends its mail through one service and one seam. Everything that will
|
|
@@ -64,6 +64,28 @@
|
|
|
64
64
|
</div>
|
|
65
65
|
|
|
66
66
|
{% if kind.type == "post" %}
|
|
67
|
+
<fieldset class="admin-editor-enclosure admin-editor-photos">
|
|
68
|
+
<legend>Photos</legend>
|
|
69
|
+
<p class="admin-hint">
|
|
70
|
+
Each is an image in the media library or an address starting https://. Leave the alt text
|
|
71
|
+
empty to use the media library’s. Empty an address to remove that photo.
|
|
72
|
+
</p>
|
|
73
|
+
{% for row in photoRows %}
|
|
74
|
+
{% set n = loop.index0 %}
|
|
75
|
+
<fieldset class="admin-editor-alternate">
|
|
76
|
+
<legend>{% if row.url %}Photo {{ loop.index }}{% else %}Add a photo{% endif %}</legend>
|
|
77
|
+
<label for="editor-photo-url-{{ n }}">Address</label>
|
|
78
|
+
<input id="editor-photo-url-{{ n }}" name="{{ photoFields.url }}{{ n }}" type="text" value="{{ row.url }}" list="editor-photo-uploads" autocomplete="off" />
|
|
79
|
+
<label for="editor-photo-alt-{{ n }}">Alt text</label>
|
|
80
|
+
<input id="editor-photo-alt-{{ n }}" name="{{ photoFields.alt }}{{ n }}" type="text" value="{{ row.alt }}"{% if row.libraryAlt %} placeholder="{{ row.libraryAlt }}"{% endif %} />
|
|
81
|
+
</fieldset>
|
|
82
|
+
{% endfor %}
|
|
83
|
+
<datalist id="editor-photo-uploads">
|
|
84
|
+
{% for url in photoChoices %}
|
|
85
|
+
<option value="{{ url }}"></option>
|
|
86
|
+
{% endfor %}
|
|
87
|
+
</datalist>
|
|
88
|
+
</fieldset>
|
|
67
89
|
<fieldset class="admin-editor-enclosure">
|
|
68
90
|
<legend>Recording</legend>
|
|
69
91
|
|
|
@@ -167,6 +189,16 @@
|
|
|
167
189
|
<label for="editor-in-reply-to">In reply to</label>
|
|
168
190
|
<input id="editor-in-reply-to" name="in-reply-to" type="url" value="{{ form.inReplyTo }}" />
|
|
169
191
|
<p class="admin-hint">The address of the post this one answers. Leave it empty for a post that answers nobody.</p>
|
|
192
|
+
|
|
193
|
+
{#- The mf2 `like-of`, `repost-of` and `bookmark-of` (TASK-169): each
|
|
194
|
+
cites a page the way a reply does, and sends it a webmention. -#}
|
|
195
|
+
<label for="editor-like-of">Like of</label>
|
|
196
|
+
<input id="editor-like-of" name="like-of" type="url" value="{{ form.likeOf }}" />
|
|
197
|
+
<label for="editor-repost-of">Repost of</label>
|
|
198
|
+
<input id="editor-repost-of" name="repost-of" type="url" value="{{ form.repostOf }}" />
|
|
199
|
+
<label for="editor-bookmark-of">Bookmark of</label>
|
|
200
|
+
<input id="editor-bookmark-of" name="bookmark-of" type="url" value="{{ form.bookmarkOf }}" />
|
|
201
|
+
<p class="admin-hint">The address of a post this one likes, reposts or bookmarks. Leave them empty for a post that cites nothing.</p>
|
|
170
202
|
{% endif %}
|
|
171
203
|
|
|
172
204
|
<label for="editor-description">Description</label>
|
|
@@ -210,6 +242,25 @@
|
|
|
210
242
|
</p>
|
|
211
243
|
{% endif %}
|
|
212
244
|
|
|
245
|
+
{% if kind.type == "post" and syndicationTargets.length %}
|
|
246
|
+
{# TASK-155: the targets content/_data/syndicationTargets.json declares.
|
|
247
|
+
A target whose tag the post carries is selected without a tick. #}
|
|
248
|
+
<fieldset class="admin-editor-syndication">
|
|
249
|
+
<legend>Syndicate to</legend>
|
|
250
|
+
{% for target in syndicationTargets %}
|
|
251
|
+
<p class="admin-check">
|
|
252
|
+
<input id="editor-{{ target.field }}" name="{{ target.field }}" type="checkbox" value="1"{% if target.checked %} checked{% endif %} />
|
|
253
|
+
<label for="editor-{{ target.field }}">{{ target.name }}</label>
|
|
254
|
+
</p>
|
|
255
|
+
{% endfor %}
|
|
256
|
+
<p class="admin-hint">
|
|
257
|
+
Writes <code>syndicate-to:</code> into the front matter. The post links to each target and
|
|
258
|
+
sends it a webmention when it is published or updated. A post tagged with a target’s tag is
|
|
259
|
+
sent there without a tick.
|
|
260
|
+
</p>
|
|
261
|
+
</fieldset>
|
|
262
|
+
{% endif %}
|
|
263
|
+
|
|
213
264
|
{# What this document says about comments, if anything. Three answers
|
|
214
265
|
rather than two: the site's own rules, always open, always closed. #}
|
|
215
266
|
<label for="editor-comments">Comments</label>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
{# /admin/syndication: the services a post can be sent to, which is
|
|
2
|
+
content/_data/syndicationTargets.json itself.
|
|
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. #}
|
|
9
|
+
{% extends "layouts/shell.njk" %}
|
|
10
|
+
{% import "components/fields.njk" as field %}
|
|
11
|
+
|
|
12
|
+
{% block title %}{{ heading }}{% endblock %}
|
|
13
|
+
|
|
14
|
+
{# The five boxes of one target, ids prefixed with the panel's key. #}
|
|
15
|
+
{% macro boxes(panel, fields) %}
|
|
16
|
+
{{ field.text(panel.key + '-id', fields.id, 'Id', panel.form.id, error=panel.problems.id,
|
|
17
|
+
spellcheck='false', required=true,
|
|
18
|
+
hint='What a post’s <code>syndicate-to</code> lists and what Micropub offers as the uid. Letters, digits, <code>.</code>, <code>-</code> and <code>_</code>.') }}
|
|
19
|
+
{{ field.text(panel.key + '-name', fields.name, 'Name', panel.form.name, error=panel.problems.name,
|
|
20
|
+
required=true, hint='What the editor’s checkbox and the post’s link say.') }}
|
|
21
|
+
{{ field.text(panel.key + '-url', fields.url, 'URL', panel.form.url, error=panel.problems.url,
|
|
22
|
+
inputmode='url', spellcheck='false', required=true,
|
|
23
|
+
hint='The page the post links to and sends its webmention to. Put <code>{lang}</code> where the post’s language goes, as in <code>https://news.indieweb.org/{lang}</code>.') }}
|
|
24
|
+
{{ field.text(panel.key + '-tag', fields.tag, 'Tag', panel.form.tag, error=panel.problems.tag,
|
|
25
|
+
spellcheck='false',
|
|
26
|
+
hint='Optional. A post carrying this tag is sent here without listing the target.') }}
|
|
27
|
+
{{ field.text(panel.key + '-languages', fields.languages, 'Languages', panel.form.languages,
|
|
28
|
+
error=panel.problems.languages, spellcheck='false',
|
|
29
|
+
hint='Optional. The language tags this target takes posts in, separated by commas, such as <code>en, de</code>. Empty takes every language.') }}
|
|
30
|
+
{% endmacro %}
|
|
31
|
+
|
|
32
|
+
{% block content %}
|
|
33
|
+
<h1>{{ heading }}</h1>
|
|
34
|
+
|
|
35
|
+
{% 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 %}
|
|
47
|
+
{% endif %}
|
|
48
|
+
|
|
49
|
+
<p class="admin-hint">
|
|
50
|
+
Services such as IndieNews and Bridgy Publish copy a post when it links to them and sends
|
|
51
|
+
them a webmention. Each target listed here gets a checkbox in the post editor and is offered
|
|
52
|
+
to Micropub clients. They are kept in <code>content/{{ file }}</code>, which this screen reads
|
|
53
|
+
and writes, so the file can still be edited by hand.
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
{% 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>
|
|
60
|
+
</div>
|
|
61
|
+
{% else %}
|
|
62
|
+
<h2>Targets</h2>
|
|
63
|
+
|
|
64
|
+
{% if panels.length %}
|
|
65
|
+
<ul class="admin-menu-boxes">
|
|
66
|
+
{% 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 %}
|
|
76
|
+
|
|
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>
|
|
86
|
+
|
|
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>
|
|
94
|
+
{% endfor %}
|
|
95
|
+
</ul>
|
|
96
|
+
{% else %}
|
|
97
|
+
<p class="admin-hint">This site declares no targets, so the editor offers none.</p>
|
|
98
|
+
{% endif %}
|
|
99
|
+
|
|
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>
|
|
109
|
+
{% endif %}
|
|
110
|
+
{% endblock %}
|
|
@@ -214,6 +214,13 @@
|
|
|
214
214
|
{% else %}
|
|
215
215
|
<span class="admin-empty">—</span>
|
|
216
216
|
{% endif %}
|
|
217
|
+
{% if row.syndication.length %}
|
|
218
|
+
<ul class="admin-syndication">
|
|
219
|
+
{% 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>
|
|
221
|
+
{% endfor %}
|
|
222
|
+
</ul>
|
|
223
|
+
{% endif %}
|
|
217
224
|
</td>
|
|
218
225
|
<td class="admin-actions">
|
|
219
226
|
<form method="post" action="{{ resendUrl }}">
|
package/admin/static/admin.css
CHANGED
|
@@ -496,6 +496,12 @@ button[type='submit']:hover,
|
|
|
496
496
|
border: 1px solid var(--admin-border);
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
+
.admin-editor-syndication {
|
|
500
|
+
margin: 1.25rem 0 0;
|
|
501
|
+
padding: 0.75rem 1rem 1rem;
|
|
502
|
+
border: 1px solid var(--admin-border);
|
|
503
|
+
}
|
|
504
|
+
|
|
499
505
|
.admin-editor-enclosure-heading {
|
|
500
506
|
margin: 1.25rem 0 0;
|
|
501
507
|
font-size: 1em;
|
|
@@ -880,6 +886,11 @@ button[type='submit']:hover,
|
|
|
880
886
|
font-weight: 600;
|
|
881
887
|
}
|
|
882
888
|
|
|
889
|
+
.admin-syndication {
|
|
890
|
+
margin: 0.25rem 0 0;
|
|
891
|
+
padding-left: 1rem;
|
|
892
|
+
}
|
|
893
|
+
|
|
883
894
|
.admin-inbox-when {
|
|
884
895
|
color: var(--admin-muted);
|
|
885
896
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import type { Context, Hono } from 'hono';
|
|
2
2
|
import type { Document, DocumentType } from '../content/document.ts';
|
|
3
|
+
import type { Enclosure } from '../content/enclosure.ts';
|
|
4
|
+
import type { Photo } from '../content/photo.ts';
|
|
3
5
|
import type { ContentStore, ListAllOptions } from '../content/store.ts';
|
|
6
|
+
import type { ResolvedConfig } from '../config.ts';
|
|
7
|
+
import type { DocumentChange } from '../content/sync.ts';
|
|
4
8
|
import type { GeekityEnv } from '../env.ts';
|
|
9
|
+
import type { UndescribedImage } from '../images/alt-text.ts';
|
|
5
10
|
import type { EnclosureForm } from './enclosure-field.ts';
|
|
11
|
+
import type { PhotoRow } from './photo-field.ts';
|
|
6
12
|
/**
|
|
7
13
|
* Everything that differs between the posts screens and the pages screens.
|
|
8
14
|
*
|
|
@@ -107,6 +113,55 @@ export interface MountDocumentScreensOptions {
|
|
|
107
113
|
* date and a taxonomy, and which section of the navigation marks itself.
|
|
108
114
|
*/
|
|
109
115
|
export declare function mountDocumentScreens(app: Hono<GeekityEnv>, options: MountDocumentScreensOptions): void;
|
|
116
|
+
/** What a write needs from the site, as plain values rather than a request. */
|
|
117
|
+
export interface DocumentSite {
|
|
118
|
+
readonly store: ContentStore;
|
|
119
|
+
readonly config: ResolvedConfig;
|
|
120
|
+
readonly announce: (change: DocumentChange) => Promise<void>;
|
|
121
|
+
/** The username of whoever is writing: the author a new document starts on. */
|
|
122
|
+
readonly writer: string | undefined;
|
|
123
|
+
}
|
|
124
|
+
/** What {@link writeDocument} is asked to write. */
|
|
125
|
+
export interface DocumentWrite {
|
|
126
|
+
readonly kind: DocumentKind;
|
|
127
|
+
/** The document being replaced, or `undefined` when one is being made. */
|
|
128
|
+
readonly document: Document | undefined;
|
|
129
|
+
readonly form: EditorForm;
|
|
130
|
+
/** Whether it is saved as a draft, which the editor's buttons decide. */
|
|
131
|
+
readonly draft: boolean;
|
|
132
|
+
}
|
|
133
|
+
/** What came of a {@link writeDocument}. */
|
|
134
|
+
export type WriteOutcome = {
|
|
135
|
+
readonly outcome: 'saved';
|
|
136
|
+
readonly saved: Document;
|
|
137
|
+
/** Images published without alt text, which the editor warns about. */
|
|
138
|
+
readonly undescribed: readonly UndescribedImage[];
|
|
139
|
+
} | {
|
|
140
|
+
readonly outcome: 'refused';
|
|
141
|
+
readonly message: string;
|
|
142
|
+
} | {
|
|
143
|
+
readonly outcome: 'conflict';
|
|
144
|
+
/** The document as the form loaded it, which only an edit has. */
|
|
145
|
+
readonly document: Document;
|
|
146
|
+
/** The recording and the photos the form resolved to. */
|
|
147
|
+
readonly media: ResolvedMedia;
|
|
148
|
+
readonly conflict: Conflict;
|
|
149
|
+
};
|
|
150
|
+
/** The post's recording and photos, as a form resolved them against the media library. */
|
|
151
|
+
interface ResolvedMedia {
|
|
152
|
+
readonly recording: Enclosure | undefined;
|
|
153
|
+
readonly photos: readonly Photo[];
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The write path behind the editor and Micropub (TASK-164): one form in, one
|
|
157
|
+
* file out, announced to every subscriber.
|
|
158
|
+
*
|
|
159
|
+
* The order matters: the form is checked before anything is touched, the
|
|
160
|
+
* on-disk file is re-hashed and compared with the hash the form loaded with
|
|
161
|
+
* (doc-1's conflict rule), and only then is a file written. A write that is
|
|
162
|
+
* refused leaves the content directory exactly as it was.
|
|
163
|
+
*/
|
|
164
|
+
export declare function writeDocument(site: DocumentSite, write: DocumentWrite): Promise<WriteOutcome>;
|
|
110
165
|
/**
|
|
111
166
|
* A comma-separated taxonomy field as a list, without the blanks and the
|
|
112
167
|
* repeats. Tags and categories are both entered this way.
|
|
@@ -135,6 +190,32 @@ export interface AuthorChoice {
|
|
|
135
190
|
* editor does and what {@link blankForm} deliberately leaves to a request.
|
|
136
191
|
*/
|
|
137
192
|
export declare function authorChoices(c: Context<GeekityEnv>, current: string): AuthorChoice[];
|
|
193
|
+
/** The file as it is now, when it is not the file the form was filled in from. */
|
|
194
|
+
interface Conflict {
|
|
195
|
+
/** The text of the file on disk. */
|
|
196
|
+
current: string;
|
|
197
|
+
/** Its hash, which is what a resubmission has to carry to go through. */
|
|
198
|
+
hash: string;
|
|
199
|
+
}
|
|
200
|
+
/** What moving a document's file needs from the site. */
|
|
201
|
+
export interface MoveSite {
|
|
202
|
+
readonly store: ContentStore;
|
|
203
|
+
readonly contentDir: string;
|
|
204
|
+
readonly announce: (change: DocumentChange) => Promise<void>;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Move a document into `content/_trash/` or back out of it, the move behind
|
|
208
|
+
* the editor's trash and restore and Micropub's delete and undelete
|
|
209
|
+
* (TASK-167). The document is the moved one, or `undefined` when its file
|
|
210
|
+
* could not be moved.
|
|
211
|
+
*
|
|
212
|
+
* The trash mirrors the content tree — `posts/2026-03-04-x.md` becomes
|
|
213
|
+
* `_trash/posts/2026-03-04-x.md` — so restoring is the same move backwards and
|
|
214
|
+
* needs to remember nothing. The index is corrected as soon as the file has
|
|
215
|
+
* landed rather than waiting for the watcher, so the public site stops or
|
|
216
|
+
* starts serving the document with this request (doc-1).
|
|
217
|
+
*/
|
|
218
|
+
export declare function moveDocumentFile(site: MoveSite, document: Document, action: 'trash' | 'restore'): Promise<Document | undefined>;
|
|
138
219
|
/**
|
|
139
220
|
* A submitted return path, when it is one this admin could have rendered.
|
|
140
221
|
*
|
|
@@ -142,6 +223,15 @@ export declare function authorChoices(c: Context<GeekityEnv>, current: string):
|
|
|
142
223
|
* as another host, so the value cannot be used to bounce somebody off the site.
|
|
143
224
|
*/
|
|
144
225
|
export declare function returnPath(value: string): string | undefined;
|
|
226
|
+
/**
|
|
227
|
+
* The editor field each citing property fills (TASK-169). The form submits it
|
|
228
|
+
* under the property's own name, as `in-reply-to` is.
|
|
229
|
+
*/
|
|
230
|
+
export declare const CITATION_FIELDS: {
|
|
231
|
+
readonly 'repost-of': 'repostOf';
|
|
232
|
+
readonly 'like-of': 'likeOf';
|
|
233
|
+
readonly 'bookmark-of': 'bookmarkOf';
|
|
234
|
+
};
|
|
145
235
|
/** The editor's fields, as strings, which is what a form has. */
|
|
146
236
|
export interface EditorForm {
|
|
147
237
|
title: string;
|
|
@@ -162,6 +252,12 @@ export interface EditorForm {
|
|
|
162
252
|
author: string;
|
|
163
253
|
/** The post this one replies to, the mf2 `in-reply-to`. Posts only. */
|
|
164
254
|
inReplyTo: string;
|
|
255
|
+
/** The post this one reposts, the mf2 `repost-of` (TASK-169). Posts only. */
|
|
256
|
+
repostOf: string;
|
|
257
|
+
/** The post this one likes, the mf2 `like-of` (TASK-169). Posts only. */
|
|
258
|
+
likeOf: string;
|
|
259
|
+
/** The page this one bookmarks, the mf2 `bookmark-of` (TASK-169). Posts only. */
|
|
260
|
+
bookmarkOf: string;
|
|
165
261
|
/** The language it is written in, the `lang` key; empty for the site's. */
|
|
166
262
|
lang: string;
|
|
167
263
|
draft: boolean;
|
|
@@ -182,6 +278,10 @@ export interface EditorForm {
|
|
|
182
278
|
comments: string;
|
|
183
279
|
/** The post's recording (TASK-213). Posts only; blank on a page. */
|
|
184
280
|
enclosure: EnclosureForm;
|
|
281
|
+
/** The post's photos (TASK-166), without the blank row the editor adds. Posts only. */
|
|
282
|
+
photos: PhotoRow[];
|
|
283
|
+
/** The ids of the declared syndication targets it selects (TASK-155). Posts only. */
|
|
284
|
+
syndicateTo: string[];
|
|
185
285
|
body: string;
|
|
186
286
|
/** The hash of the file the form was filled in from; empty for a new one. */
|
|
187
287
|
hash: string;
|
|
@@ -248,4 +348,5 @@ export declare const PAGE_ROLE_LABELS: {
|
|
|
248
348
|
};
|
|
249
349
|
/** The URL of one view of a listing. Page one is the listing's own URL. */
|
|
250
350
|
export declare function listingUrl(kind: DocumentKind, filter: DocumentFilter, page?: number): string;
|
|
351
|
+
export {};
|
|
251
352
|
//# sourceMappingURL=documents.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/admin/documents.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/admin/documents.ts"],"names":[],"mappings":"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"}
|