@geekity/cms 0.29.0 → 0.30.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 (52) hide show
  1. package/README.md +84 -32
  2. package/dist/admin/store.d.ts +42 -15
  3. package/dist/admin/store.d.ts.map +1 -1
  4. package/dist/admin/store.js +71 -31
  5. package/dist/admin/store.js.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +10 -3
  8. package/dist/cli.js.map +1 -1
  9. package/dist/comments/index.d.ts +2 -2
  10. package/dist/comments/index.d.ts.map +1 -1
  11. package/dist/comments/index.js +1 -1
  12. package/dist/comments/index.js.map +1 -1
  13. package/dist/comments/records.d.ts +32 -4
  14. package/dist/comments/records.d.ts.map +1 -1
  15. package/dist/comments/records.js +182 -9
  16. package/dist/comments/records.js.map +1 -1
  17. package/dist/comments/routes.js +3 -3
  18. package/dist/comments/routes.js.map +1 -1
  19. package/dist/federation/backfill.js +6 -4
  20. package/dist/federation/backfill.js.map +1 -1
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +4 -3
  24. package/dist/index.js.map +1 -1
  25. package/dist/plugin.d.ts +28 -2
  26. package/dist/plugin.d.ts.map +1 -1
  27. package/dist/plugin.js +10 -2
  28. package/dist/plugin.js.map +1 -1
  29. package/dist/plugins/site.d.ts.map +1 -1
  30. package/dist/plugins/site.js +7 -1
  31. package/dist/plugins/site.js.map +1 -1
  32. package/dist/web/conversation.d.ts +47 -23
  33. package/dist/web/conversation.d.ts.map +1 -1
  34. package/dist/web/conversation.js +151 -120
  35. package/dist/web/conversation.js.map +1 -1
  36. package/dist/web/feed-source.d.ts +10 -7
  37. package/dist/web/feed-source.d.ts.map +1 -1
  38. package/dist/web/feed-source.js +21 -13
  39. package/dist/web/feed-source.js.map +1 -1
  40. package/dist/web/guids.d.ts +4 -16
  41. package/dist/web/guids.d.ts.map +1 -1
  42. package/dist/web/guids.js +5 -17
  43. package/dist/web/guids.js.map +1 -1
  44. package/dist/web/routes.d.ts.map +1 -1
  45. package/dist/web/routes.js +63 -53
  46. package/dist/web/routes.js.map +1 -1
  47. package/dist/webmention/receive.js +5 -5
  48. package/dist/webmention/receive.js.map +1 -1
  49. package/package.json +1 -1
  50. package/themes/default/README.md +41 -31
  51. package/themes/default/layouts/comment.njk +3 -3
  52. package/themes/default/partials/comment.njk +5 -5
@@ -1968,32 +1968,42 @@ the thread, because it is not an answer.
1968
1968
 
1969
1969
  Each entry — a reply, a like or a boost — is:
1970
1970
 
1971
- | Key | What it holds |
1972
- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1973
- | `id` | What it is called: a reply's own note id, which is what an answer to it names. |
1974
- | `source` | `"activitypub"` for a fediverse reply, `"comment"` for one left on the page, `"webmention"` for another page linking here, `"post"` for a reply post a user of the site wrote (its `url` is the post's permalink). |
1975
- | `kind` | `"reply"`, `"like"`, `"boost"`, `"repost"` or `"mention"`. A `repost` comes from a webmention; a `mention` is a webmention or an approved fediverse quote. |
1976
- | `author.name` | The best name available: their display name, else their handle, else their server, else their id. For a webmention, the source's `h-card` name, else its host. |
1977
- | `author.handle` | `@user@host`, or `null`. Taken from the follower or actor profile the site holds, else guessed from the actor URL unless it ends in a number. `null` for a native comment. |
1978
- | `author.url` | Their profile page, the website a commenter typed, or a webmention author's `u-url`. May be `null`, so guard the link. |
1979
- | `author.avatar` | Their avatar, or `null`. The site knows one for a fediverse actor whose profile it holds and for a webmention whose `h-card` carried a `u-photo`. Always a same-origin `/_geekity/avatars/…` path, never the remote URL: see [Avatars](#avatars). |
1980
- | `author.actorId` | Their id, which is what identifies them however they are named. `null` for a native comment. |
1981
- | `url` | Where it can be read: the remote note's `url` for a fediverse reply or quote, the source page for a webmention, and `/comment/{id}/`, its own page, for a native comment (see [A comment's own page](#a-comments-own-page)). |
1982
- | `content` | What it says, **already sanitised**, so print it with `\| safe`. Empty for a like or a boost. |
1983
- | `published` | A `Date`: when it was published, or when it arrived if it did not say. Use the `date` filter. |
1984
- | `inReplyTo` | What it answers — the post's ActivityPub id, or another reply's — and `null` for a reaction. |
1985
- | `status` | `"published"`. On the record for the sources that moderate. |
1986
- | `replies` | The replies to this one, oldest first, nested as deep as the site has seen. One may be a placeholder: see below. |
1987
- | `rsvp` | An RSVP: `{ value, label }`, its `p-rsvp` (`yes`, `no`, `maybe` or `interested`) and the words for it. Absent otherwise. A webmention reply that is an RSVP carries one, and the default theme prints it as a `data.p-rsvp` at the top of the comment's content. On an event, an RSVP is in `rsvps` rather than the thread, and so is a fediverse `Accept` (`yes`), `TentativeAccept` (`maybe`) or `Reject` (`no`) of the event. Each person is there once, with their latest answer. |
1971
+ | Key | What it holds |
1972
+ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1973
+ | `id` | What it is called: a fediverse reply's note id, a reaction's activity id, a stored comment's key. It is what an answer to it names. |
1974
+ | `key` | Its key (decision-51): 16 lowercase hex digits, the comment's id for one stored on the site and the key of its guid for anything else. Its anchor is `#comment-{key}` and its replies feed `/replies/{key}/`. |
1975
+ | `guid` | What the comments feeds call it: a native comment's `/comment/{key}/` page, a stored comment's origin (else its `url`), a fediverse note's id, a reply post's object id. |
1976
+ | `migrated` | `true` for a comment imported from the site this one replaced (decision-51). It shows like any other, but no feed carries it and no count a feed advertises includes it. |
1977
+ | `source` | `"activitypub"` for a fediverse reply, `"comment"` for one left on the page, `"webmention"` for another page linking here, `"post"` for a reply post a user of the site wrote (its `url` is the post's permalink). |
1978
+ | `kind` | `"reply"`, `"like"`, `"boost"`, `"repost"` or `"mention"`. A `repost` comes from a webmention; a `mention` is a webmention or an approved fediverse quote. |
1979
+ | `author.name` | The best name available: their display name, else their handle, else their server, else their id. For a webmention, the source's `h-card` name, else its host. |
1980
+ | `author.handle` | `@user@host`, or `null`. Taken from the follower or actor profile the site holds, else guessed from the actor URL unless it ends in a number. `null` for a native comment. |
1981
+ | `author.url` | Their profile page, the website a commenter typed, or a webmention author's `u-url`. May be `null`, so guard the link. |
1982
+ | `author.avatar` | Their avatar, or `null`. The site knows one for a fediverse actor whose profile it holds or whose imported comment brought their icon, and for a webmention whose `h-card` carried a `u-photo`. Always a same-origin `/_geekity/avatars/…` path, never the remote URL: see [Avatars](#avatars). |
1983
+ | `author.actorId` | Their id, which is what identifies them however they are named. `null` for a native comment, and for an imported one whose actor the export did not name. |
1984
+ | `author.username` | The site user they are, or `null`: whoever wrote a reply post, or the user a comment imported from the site this one replaced names (a WordPress comment written signed in). Such a comment's `author` is that user's, as a reply post's is: their display name, avatar and author archive. |
1985
+ | `url` | Where it can be read: the remote note's `url` for a fediverse reply or quote, the source page for a webmention, and `/comment/{key}/`, its own page, for a native comment (see [A comment's own page](#a-comments-own-page)). |
1986
+ | `content` | What it says, **already sanitised**, so print it with `\| safe`. Empty for a like or a boost. |
1987
+ | `published` | A `Date`: when it was published, or when it arrived if it did not say. Use the `date` filter. |
1988
+ | `inReplyTo` | What it answers — the post's ActivityPub id, or another reply's — and `null` for a reaction. |
1989
+ | `status` | `"published"`. On the record for the sources that moderate. |
1990
+ | `replies` | The replies to this one, oldest first, nested as deep as the site has seen. One may be a placeholder: see below. |
1991
+ | `rsvp` | An RSVP: `{ value, label }`, its `p-rsvp` (`yes`, `no`, `maybe` or `interested`) and the words for it. Absent otherwise. A webmention reply that is an RSVP carries one, and the default theme prints it as a `data.p-rsvp` at the top of the comment's content. On an event, an RSVP is in `rsvps` rather than the thread, and so is a fediverse `Accept` (`yes`), `TentativeAccept` (`maybe`) or `Reject` (`no`) of the event. Each person is there once, with their latest answer. |
1988
1992
 
1989
1993
  Four rules decide what is in the thread, and they are the CMS's rather than a
1990
1994
  theme's: a reply whose author deleted it is gone, and its own answers move up to
1991
1995
  whatever it was answering; a comment a reader may not see (waiting for a
1992
1996
  moderator, spam or deleted) that has a visible reply under it is a placeholder,
1993
- and one with none is not there at all; a like is counted once per actor and
1994
- disappears when that actor undoes it; and a note answering something this post
1997
+ and one with none is not there at all; a like is counted once per actor,
1998
+ so an imported like and the same actor's like
1999
+ delivered here are one, and it disappears when that actor undoes it; and a note answering something this post
1995
2000
  has nothing to do with is left out.
1996
2001
 
2002
+ A fediverse reply or reaction imported from the site this one replaced is
2003
+ shown once, however often its server sends it again or the reply backfill
2004
+ reads it: the imported comment is the one in the thread, with the moderator's
2005
+ decision on it, and the answers to its note thread under it.
2006
+
1997
2007
  A placeholder in `replies` is `{ id, withheld: true, replies }`: the hidden
1998
2008
  comment's id and the replies under it, and nothing that names its author or
1999
2009
  says what it said. Test `reply.withheld` before printing an author. A pending
@@ -2011,18 +2021,18 @@ and every link carrying `rel="nofollow ugc"`. Nothing else survives any of the
2011
2021
  three routes, so a theme may print all of them directly.
2012
2022
 
2013
2023
  The packaged partial draws each entry as the source design does: an
2014
- `li.comment.h-entry` carrying `id="comment-{{ reply.id }}"` and a
2024
+ `li.comment.h-entry` carrying `id="comment-{{ reply.key }}"` and a
2015
2025
  `comment-{{ reply.source }}` class, holding an `article.comment-body` whose
2016
2026
  `footer.comment-meta` is the author as a `.comment-author.vcard.p-author.h-card`
2017
2027
  (their avatar, or the first letter of their name in a `span.comment-avatar-empty`
2018
- when there is none, and their link marked `rel="nofollow ugc"` unless the entry
2019
- is a reply post, whose author is a user of the site) and the permalink as a `.comment-metadata` link around a
2028
+ when there is none, and their link marked `rel="nofollow ugc"` unless `author.username` says the
2029
+ author is a user of the site, as a reply post's author is) and the permalink as a `.comment-metadata` link around a
2020
2030
  `time.dt-published`, with a `span.comment-source` saying "via webmention" or
2021
2031
  "via the fediverse" when it came that way, then the words in
2022
2032
  `div.comment-content.e-content`. Answers nest in an
2023
2033
  `ol.children` inside what they answer. A Reply link in a `div.reply` goes on the
2024
2034
  ones written here — `source == "comment"` — when the post is still open; it
2025
- carries the comment's id to the form as `?reply_to=`, so threading needs no
2035
+ carries the comment's key to the form as `?reply_to=`, so threading needs no
2026
2036
  JavaScript. A fediverse reply is answered on the server that holds it and a
2027
2037
  webmention on the page that sent it, so neither gets one. A placeholder is an
2028
2038
  `li.comment.comment-placeholder` with the hidden comment's anchor, a
@@ -2057,17 +2067,17 @@ An Eleventy build of the same content gets the same thing from the same files:
2057
2067
  and then loops over exactly the keys above. The slug is what names the post's
2058
2068
  comment file under `content/_data/comments/`; the format is documented in
2059
2069
  backlog doc-6. Two things differ: a native comment's `url` is its
2060
- `#comment-{id}` anchor, because a static build writes no comment pages, and
2070
+ `#comment-{key}` anchor, because a static build writes no comment pages, and
2061
2071
  the site's own reply posts (`source: "post"`) are not in the thread.
2062
2072
 
2063
2073
  ### A comment's own page
2064
2074
 
2065
- A comment left through the form has a page of its own at `/comment/{id}/`,
2066
- with the id percent-encoded, which is its `url` everywhere: the thread's
2067
- permalink, the comments feeds and what another site fetches when it replies
2068
- to the comment. The anchor `#comment-{id}` on the post stays, so an old link
2069
- still scrolls to it. A webmention and a fediverse reply have no such page:
2070
- their `url` is where they came from.
2075
+ A comment left through the form has a page of its own at `/comment/{key}/`,
2076
+ which is its `url` everywhere: the thread's permalink, the comments feeds and
2077
+ what another site fetches when it replies to the comment. The anchor
2078
+ `#comment-{key}` on the post stays, so an old link still scrolls to it. A
2079
+ webmention and a fediverse reply have no such page: their `url` is where they
2080
+ came from.
2071
2081
 
2072
2082
  `layouts/comment.njk` draws it, with the comment as the page's one `h-entry`.
2073
2083
  It answers only while the post shows its conversation, and is `noindex` and on
@@ -2210,7 +2220,7 @@ labelled "Include in posts and feeds" and unchecked by default: unchecked
2210
2220
  publishes the reply post unlisted, checked publishes it public. The stranger's
2211
2221
  branch never draws it, and the CMS ignores it from a stranger.
2212
2222
 
2213
- A Reply link, `?reply_to={id}#respond`, goes on every entry of the thread for
2223
+ A Reply link, `?reply_to={key}#respond`, goes on every entry of the thread for
2214
2224
  somebody signed in, and on `source == "comment"` entries only for a stranger.
2215
2225
  `partials/comment.njk` asks `reply.source == "comment" or
2216
2226
  commentForm.signedInAs`.
@@ -1,5 +1,5 @@
1
1
  {#
2
- A native comment on a page of its own (TASK-318), at `/comment/{id}/`: what
2
+ A native comment on a page of its own (TASK-318), at `/comment/{key}/`: what
3
3
  another site fetches when it replies to the comment, so the comment is the
4
4
  page's one `h-entry`.
5
5
 
@@ -38,7 +38,7 @@
38
38
  {{ cited(index - 1) }}
39
39
  {% if step %}
40
40
  <p class="cite-line">
41
- <span class="p-author h-card">{% if step.author.url %}<a class="u-url p-name" href="{{ step.author.url }}"{% if step.source != "post" %} rel="nofollow ugc noopener noreferrer"{% endif %}>{{ step.author.name }}</a>{% else %}<span class="p-name">{{ step.author.name }}</span>{% endif %}</span>,
41
+ <span class="p-author h-card">{% if step.author.url %}<a class="u-url p-name" href="{{ step.author.url }}"{% if not step.author.username %} rel="nofollow ugc noopener noreferrer"{% endif %}>{{ step.author.name }}</a>{% else %}<span class="p-name">{{ step.author.name }}</span>{% endif %}</span>,
42
42
  {%- if step.url %}
43
43
  <a class="u-url" href="{{ step.url }}"{% if step.source != "comment" %} rel="nofollow noopener noreferrer"{% endif %}><time class="dt-published" datetime="{{ step.published | date("iso") }}">{{ step.published | date }}</time></a>
44
44
  {%- else %}
@@ -67,7 +67,7 @@
67
67
  {%- else %}
68
68
  <span class="comment-avatar-empty" aria-hidden="true">{{ comment.author.name | first | upper }}</span>
69
69
  {%- endif %}
70
- <b class="p-name">{% if comment.author.url %}<a class="u-url" href="{{ comment.author.url }}" rel="nofollow ugc noopener noreferrer">{{ comment.author.name }}</a>{% else %}{{ comment.author.name }}{% endif %}</b>
70
+ <b class="p-name">{% if comment.author.url %}<a class="u-url" href="{{ comment.author.url }}"{% if not comment.author.username %} rel="nofollow ugc noopener noreferrer"{% endif %}>{{ comment.author.name }}</a>{% else %}{{ comment.author.name }}{% endif %}</b>
71
71
  </div>
72
72
  <div class="comment-metadata">
73
73
  <a class="u-url" href="{{ comment.url }}"><time class="dt-published" datetime="{{ comment.published | date("iso") }}">{{ comment.published | date }}</time></a>
@@ -15,7 +15,7 @@
15
15
 
16
16
  {% macro comment(reply, classes="h-entry") %}
17
17
  {% if reply.withheld %}
18
- <li id="comment-{{ reply.id }}" class="comment comment-placeholder">
18
+ <li id="comment-{{ reply.key }}" class="comment comment-placeholder">
19
19
  <p class="comment-withheld">{{ withheld() }}</p>
20
20
  <ol class="children">
21
21
  {% for child in reply.replies %}
@@ -24,7 +24,7 @@
24
24
  </ol>
25
25
  </li>
26
26
  {% else %}
27
- <li id="comment-{{ reply.id }}" class="comment {{ classes }} comment-{{ reply.source }}">
27
+ <li id="comment-{{ reply.key }}" class="comment {{ classes }} comment-{{ reply.source }}">
28
28
  <article class="comment-body">
29
29
  <footer class="comment-meta">
30
30
  <div class="comment-author vcard p-author h-card">
@@ -33,7 +33,7 @@
33
33
  {%- else %}
34
34
  <span class="comment-avatar-empty" aria-hidden="true">{{ reply.author.name | first | upper }}</span>
35
35
  {%- endif %}
36
- <b class="fn p-name">{% if reply.author.url %}<a class="url u-url" href="{{ reply.author.url }}"{% if reply.source != "post" %} rel="nofollow ugc noopener noreferrer"{% endif %}>{{ reply.author.name }}</a>{% else %}{{ reply.author.name }}{% endif %}</b>
36
+ <b class="fn p-name">{% if reply.author.url %}<a class="url u-url" href="{{ reply.author.url }}"{% if not reply.author.username %} rel="nofollow ugc noopener noreferrer"{% endif %}>{{ reply.author.name }}</a>{% else %}{{ reply.author.name }}{% endif %}</b>
37
37
  </div>
38
38
  <div class="comment-metadata">
39
39
  {%- if reply.url %}
@@ -56,7 +56,7 @@
56
56
  </div>
57
57
  {#
58
58
  Answering a comment on this site needs no JavaScript: the link carries
59
- the comment's id to the form, which puts it in a hidden field. Somebody
59
+ the comment's key to the form, which puts it in a hidden field. Somebody
60
60
  signed in can answer anything in the thread, and their answer is a reply
61
61
  post that reaches a webmention's page or a fediverse reply's author
62
62
  (TASK-300). A visitor answers comments written here only: a fediverse
@@ -64,7 +64,7 @@
64
64
  page that sent it.
65
65
  #}
66
66
  {% if commentForm and (reply.source == "comment" or commentForm.signedInAs) %}
67
- <div class="reply"><a class="comment-reply-link" href="{{ page.url }}?reply_to={{ reply.id | urlencode }}#respond">Reply</a></div>
67
+ <div class="reply"><a class="comment-reply-link" href="{{ page.url }}?reply_to={{ reply.key }}#respond">Reply</a></div>
68
68
  {% endif %}
69
69
  </article>
70
70
  {% if reply.replies.length %}