@geekity/cms 0.28.0 → 0.29.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 +303 -53
- package/admin/pages/comments/all.njk +3 -1
- package/admin/pages/federation/followers.njk +8 -2
- package/dist/admin/comments.d.ts +2 -0
- package/dist/admin/comments.d.ts.map +1 -1
- package/dist/admin/comments.js +19 -49
- package/dist/admin/comments.js.map +1 -1
- package/dist/admin/documents.d.ts +5 -0
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +45 -17
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/federation.d.ts +21 -1
- package/dist/admin/federation.d.ts.map +1 -1
- package/dist/admin/federation.js +17 -7
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/store.d.ts +64 -10
- package/dist/admin/store.d.ts.map +1 -1
- package/dist/admin/store.js +166 -17
- package/dist/admin/store.js.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/comments/form.d.ts +3 -1
- package/dist/comments/form.d.ts.map +1 -1
- package/dist/comments/form.js +2 -1
- package/dist/comments/form.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 +24 -20
- package/dist/comments/records.d.ts.map +1 -1
- package/dist/comments/records.js +74 -23
- package/dist/comments/records.js.map +1 -1
- package/dist/comments/reply-notices.d.ts +42 -0
- package/dist/comments/reply-notices.d.ts.map +1 -0
- package/dist/comments/reply-notices.js +76 -0
- package/dist/comments/reply-notices.js.map +1 -0
- package/dist/comments/reply-post.d.ts +49 -0
- package/dist/comments/reply-post.d.ts.map +1 -0
- package/dist/comments/reply-post.js +66 -0
- package/dist/comments/reply-post.js.map +1 -0
- package/dist/comments/routes.d.ts +6 -1
- package/dist/comments/routes.d.ts.map +1 -1
- package/dist/comments/routes.js +49 -21
- package/dist/comments/routes.js.map +1 -1
- package/dist/comments/submission.d.ts +8 -25
- package/dist/comments/submission.d.ts.map +1 -1
- package/dist/comments/submission.js +19 -38
- package/dist/comments/submission.js.map +1 -1
- package/dist/comments/viewer.d.ts.map +1 -1
- package/dist/comments/viewer.js +1 -0
- package/dist/comments/viewer.js.map +1 -1
- package/dist/content/citation.d.ts +1 -0
- package/dist/content/citation.d.ts.map +1 -1
- package/dist/content/citation.js +2 -0
- package/dist/content/citation.js.map +1 -1
- package/dist/content/original.d.ts +6 -1
- package/dist/content/original.d.ts.map +1 -1
- package/dist/content/original.js +7 -4
- package/dist/content/original.js.map +1 -1
- package/dist/content/store.d.ts +43 -11
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js +170 -10
- package/dist/content/store.js.map +1 -1
- package/dist/content/sync.d.ts +8 -0
- package/dist/content/sync.d.ts.map +1 -1
- package/dist/content/sync.js +164 -71
- package/dist/content/sync.js.map +1 -1
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +2 -1
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/backfill.d.ts +114 -0
- package/dist/federation/backfill.d.ts.map +1 -0
- package/dist/federation/backfill.js +312 -0
- package/dist/federation/backfill.js.map +1 -0
- package/dist/federation/inbox.js +1 -1
- package/dist/federation/inbox.js.map +1 -1
- package/dist/federation/records.d.ts +13 -0
- package/dist/federation/records.d.ts.map +1 -1
- package/dist/federation/records.js +49 -10
- package/dist/federation/records.js.map +1 -1
- package/dist/federation/replies.d.ts +6 -0
- package/dist/federation/replies.d.ts.map +1 -1
- package/dist/federation/replies.js +18 -1
- package/dist/federation/replies.js.map +1 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +79 -10
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +1 -7
- package/dist/init.js.map +1 -1
- package/dist/web/context.d.ts +18 -3
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +17 -4
- package/dist/web/context.js.map +1 -1
- package/dist/web/conversation.d.ts +155 -16
- package/dist/web/conversation.d.ts.map +1 -1
- package/dist/web/conversation.js +602 -135
- package/dist/web/conversation.js.map +1 -1
- package/dist/web/documents.d.ts +0 -22
- package/dist/web/documents.d.ts.map +1 -1
- package/dist/web/documents.js +1 -34
- package/dist/web/documents.js.map +1 -1
- package/dist/web/feed-item.d.ts +12 -8
- package/dist/web/feed-item.d.ts.map +1 -1
- package/dist/web/feed-item.js +10 -10
- package/dist/web/feed-item.js.map +1 -1
- package/dist/web/feed-rss.d.ts.map +1 -1
- package/dist/web/feed-rss.js +34 -10
- package/dist/web/feed-rss.js.map +1 -1
- package/dist/web/feed-source.d.ts +30 -1
- package/dist/web/feed-source.d.ts.map +1 -1
- package/dist/web/feed-source.js +25 -0
- package/dist/web/feed-source.js.map +1 -1
- package/dist/web/feeds.d.ts +1 -1
- package/dist/web/feeds.d.ts.map +1 -1
- package/dist/web/feeds.js +7 -2
- package/dist/web/feeds.js.map +1 -1
- package/dist/web/guids.d.ts +59 -0
- package/dist/web/guids.d.ts.map +1 -0
- package/dist/web/guids.js +79 -0
- package/dist/web/guids.js.map +1 -0
- package/dist/web/index.d.ts +5 -6
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +3 -3
- package/dist/web/index.js.map +1 -1
- package/dist/web/redirects.d.ts +12 -0
- package/dist/web/redirects.d.ts.map +1 -1
- package/dist/web/redirects.js +16 -4
- package/dist/web/redirects.js.map +1 -1
- package/dist/web/render.d.ts +19 -9
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +44 -42
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts +2 -2
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +94 -31
- package/dist/web/routes.js.map +1 -1
- package/dist/webmention/index.d.ts +1 -1
- package/dist/webmention/index.d.ts.map +1 -1
- package/dist/webmention/index.js +1 -1
- package/dist/webmention/index.js.map +1 -1
- package/dist/webmention/links.d.ts +55 -0
- package/dist/webmention/links.d.ts.map +1 -1
- package/dist/webmention/links.js +162 -0
- package/dist/webmention/links.js.map +1 -1
- package/dist/webmention/microformats.d.ts +15 -0
- package/dist/webmention/microformats.d.ts.map +1 -1
- package/dist/webmention/microformats.js +63 -1
- package/dist/webmention/microformats.js.map +1 -1
- package/dist/webmention/pingback.js +2 -1
- package/dist/webmention/pingback.js.map +1 -1
- package/dist/webmention/receive.d.ts +5 -0
- package/dist/webmention/receive.d.ts.map +1 -1
- package/dist/webmention/receive.js +99 -3
- package/dist/webmention/receive.js.map +1 -1
- package/dist/webmention/reply-context.d.ts +15 -0
- package/dist/webmention/reply-context.d.ts.map +1 -1
- package/dist/webmention/reply-context.js +29 -0
- package/dist/webmention/reply-context.js.map +1 -1
- package/dist/webmention/reply-contexts.d.ts +6 -0
- package/dist/webmention/reply-contexts.d.ts.map +1 -1
- package/dist/webmention/reply-contexts.js +16 -10
- package/dist/webmention/reply-contexts.js.map +1 -1
- package/dist/webmention/routes.d.ts.map +1 -1
- package/dist/webmention/routes.js +2 -1
- package/dist/webmention/routes.js.map +1 -1
- package/dist/webmention/service.d.ts +30 -1
- package/dist/webmention/service.d.ts.map +1 -1
- package/dist/webmention/service.js +172 -32
- package/dist/webmention/service.js.map +1 -1
- package/package.json +1 -2
- package/themes/default/README.md +242 -78
- package/themes/default/layouts/base.njk +8 -0
- package/themes/default/layouts/comment.njk +90 -0
- package/themes/default/layouts/front-page.njk +9 -47
- package/themes/default/layouts/page.njk +2 -0
- package/themes/default/layouts/post.njk +14 -2
- package/themes/default/partials/backlinks.njk +19 -0
- package/themes/default/partials/cited-page.njk +3 -1
- package/themes/default/partials/comment-form.njk +10 -0
- package/themes/default/partials/comment.njk +79 -0
- package/themes/default/partials/conversation.njk +14 -59
- package/themes/default/src/style.css +42 -0
- package/themes/default/static/style.css +67 -0
|
@@ -1,60 +1,22 @@
|
|
|
1
1
|
{#
|
|
2
|
-
The front page: the page the Reading setting names, read at
|
|
3
|
-
source design's `front-page.php` draws it (decision-16, TASK-85).
|
|
2
|
+
The front page: the page the Reading setting names, read at `/`.
|
|
4
3
|
|
|
5
|
-
A site
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
over the same feed a listing is made of, headed at 3 so the outline never
|
|
11
|
-
skips a level, then the line of links, then the bio.
|
|
12
|
-
|
|
13
|
-
The bio is the site's author's on a solo author blog, with the `rel="me"`
|
|
14
|
-
claims that make this page their identity (TASK-180). On any other site it is
|
|
15
|
-
whoever the page is by, and it claims nothing: the homepage speaks for nobody.
|
|
16
|
-
|
|
17
|
-
A theme that wants a different front page replaces this file; a site that
|
|
18
|
-
wants no front page of its own sets no homepage, and `/` is the listing.
|
|
4
|
+
A site that wants more on its front page overrides this file in its own
|
|
5
|
+
theme. `newestPosts(count)` lists the newest published posts as listing
|
|
6
|
+
entries and `postsPage` names the page carrying the listing; the theme README
|
|
7
|
+
has an example. On a solo author site the base layout keeps the homepage's
|
|
8
|
+
`rel="me"` claims in the head whatever this file prints (decision-45).
|
|
19
9
|
#}
|
|
20
10
|
{% extends "layouts/base.njk" %}
|
|
21
11
|
|
|
22
|
-
{#- Who the bio credits: the person the site's author setting names. -#}
|
|
23
|
-
{% set bioAuthor = soloAuthor or siteAuthor %}
|
|
24
|
-
{% set bioRelMe = true if soloAuthor else false %}
|
|
25
|
-
{% set bioHome = "/" | absoluteUrl if soloAuthor else "" %}
|
|
26
|
-
|
|
27
12
|
{% block content %}
|
|
13
|
+
{% if title %}
|
|
14
|
+
<h2 class="section-title">{{ title }}</h2>
|
|
15
|
+
{% endif %}
|
|
28
16
|
<div class="page-body e-content">
|
|
29
17
|
{{ content | safe }}
|
|
30
18
|
</div>
|
|
31
19
|
|
|
32
|
-
<h2 class="section-title">Recent Posts</h2>
|
|
33
|
-
{#- The feed a listing prints, over the posts the CMS decided were recent:
|
|
34
|
-
this month's writing when there is enough of it and the five newest
|
|
35
|
-
otherwise. `feedHeading` is 3 because the `h2` above is what they sit
|
|
36
|
-
under. -#}
|
|
37
|
-
{% set posts = recentPosts %}
|
|
38
|
-
{% set feedHeading = 3 %}
|
|
39
|
-
{% include "partials/post-list.njk" %}
|
|
40
|
-
|
|
41
|
-
{#- Where to go next. The posts page is here only when the site has one — on a
|
|
42
|
-
site without one there is no second URL for the archive, and a link to one
|
|
43
|
-
would be a link to nothing. Search is always here (TASK-22). -#}
|
|
44
|
-
<p class="front-links">
|
|
45
|
-
{% if postsPage %}
|
|
46
|
-
<a href="{{ postsPage.url | url }}">{{ postsPage.title }}<span aria-hidden="true"> →</span></a>
|
|
47
|
-
{% endif %}
|
|
48
|
-
<a href="{{ "/search/" | url }}">Search<span aria-hidden="true"> →</span></a>
|
|
49
|
-
</p>
|
|
50
|
-
|
|
51
|
-
{% if bioAuthor %}
|
|
52
|
-
<hr>
|
|
53
|
-
<footer>
|
|
54
|
-
{% include "partials/bio.njk" %}
|
|
55
|
-
</footer>
|
|
56
|
-
{% endif %}
|
|
57
|
-
|
|
58
20
|
{# A homepage may ask for a contact form like any other page (TASK-56). #}
|
|
59
21
|
{% if contactForm %}
|
|
60
22
|
{% include "partials/contact-form.njk" %}
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
`p-summary`. A post with no title opens on its words, set larger. What a
|
|
10
10
|
reply answers, and what a like, repost or bookmark cites, opens a post with
|
|
11
11
|
no title and follows the header of one with a title, before its words.
|
|
12
|
-
Then the Published line, the tags, a rule and the bio. The
|
|
13
|
-
the
|
|
12
|
+
Then the Published line, the tags, a rule and the bio. The site's own posts
|
|
13
|
+
that link to it, the neighbouring posts, the conversation and the comment
|
|
14
|
+
form follow the entry.
|
|
14
15
|
|
|
15
16
|
The Published line is inside the `e-content` on purpose. It is what the
|
|
16
17
|
source design does, and it is what makes a reader who copies the words out
|
|
@@ -118,8 +119,18 @@
|
|
|
118
119
|
{% include "partials/bio.njk" %}
|
|
119
120
|
</footer>
|
|
120
121
|
{% endif %}
|
|
122
|
+
{#- A reply post's replies are inside its entry as `p-comment h-cite`s, so
|
|
123
|
+
the page it answers reads them there when it is sent a salmention
|
|
124
|
+
(TASK-320). The likes and boosts stay below: their links are not the
|
|
125
|
+
entry's. -#}
|
|
126
|
+
{% if conversation and postType == "reply" %}
|
|
127
|
+
{% set conversationPart = "replies" %}
|
|
128
|
+
{% include "partials/conversation.njk" %}
|
|
129
|
+
{% endif %}
|
|
121
130
|
</article>
|
|
122
131
|
|
|
132
|
+
{% include "partials/backlinks.njk" %}
|
|
133
|
+
|
|
123
134
|
{# The post either side of this one, as two cards. Each is on the context only
|
|
124
135
|
when there is one, so the ends of the archive draw one card and a site of a
|
|
125
136
|
single post draws none. #}
|
|
@@ -138,6 +149,7 @@
|
|
|
138
149
|
|
|
139
150
|
{# Only a post that has been replied to, liked or boosted has one of these. #}
|
|
140
151
|
{% if conversation %}
|
|
152
|
+
{% set conversationPart = "reactions" if postType == "reply" else "all" %}
|
|
141
153
|
{% include "partials/conversation.njk" %}
|
|
142
154
|
{% endif %}
|
|
143
155
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{#
|
|
2
|
+
The site's own posts and pages that link to this one (TASK-322), newest
|
|
3
|
+
first: what a link between two of its posts is instead of a webmention, so
|
|
4
|
+
it is listed apart from the conversation rather than counted in it.
|
|
5
|
+
|
|
6
|
+
`backlinks` is always a list, each entry `{ title, url, date }`, with no
|
|
7
|
+
`date` for a page that has none. An empty list prints nothing, so a layout
|
|
8
|
+
includes this unconditionally.
|
|
9
|
+
#}
|
|
10
|
+
{% if backlinks.length %}
|
|
11
|
+
<section class="backlinks" aria-labelledby="backlinks-title">
|
|
12
|
+
<h2 id="backlinks-title" class="backlinks-title">Linked from</h2>
|
|
13
|
+
<ol>
|
|
14
|
+
{% for link in backlinks %}
|
|
15
|
+
<li><a href="{{ link.url | url }}">{{ link.title }}</a>{% if link.date %} <time datetime="{{ link.date | date("iso") }}">{{ link.date | date("readable") }}</time>{% endif %}</li>
|
|
16
|
+
{% endfor %}
|
|
17
|
+
</ol>
|
|
18
|
+
</section>
|
|
19
|
+
{% endif %}
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
`url` is the cited page, always its `u-url`. `context` is what the page said
|
|
10
10
|
about itself, from the reply contexts file. With a name, the name is the
|
|
11
|
-
link;
|
|
11
|
+
link; a comment on this site (`context.comment`, TASK-326) is "a comment";
|
|
12
|
+
with only an author, "a post" is; a URL that is itself an image
|
|
12
13
|
(`context.image`, TASK-255) is "an image from" its host; anything else is "a
|
|
13
14
|
page on" its host, never the bare URL, which can run to hundreds of
|
|
14
15
|
characters. The author follows as an `h-card`.
|
|
@@ -42,6 +43,7 @@
|
|
|
42
43
|
{%- if named %} <span class="p-name"><a class="u-url" href="{{ url }}">{{ title.slice(0, cut) }}</a>{{ byline.slice(0, 4) }}{{ card(context.author, byline.slice(4)) }}</span>
|
|
43
44
|
{%- else %}
|
|
44
45
|
{%- if context.name %} <a class="u-url p-name" href="{{ url }}">{{ context.name }}</a>
|
|
46
|
+
{%- elif context.comment %} <a class="u-url" href="{{ url }}">a comment</a>
|
|
45
47
|
{%- elif context.author %} <a class="u-url" href="{{ url }}">a post</a>
|
|
46
48
|
{%- elif context.image %} <a class="u-url" href="{{ url }}">an image from {{ url | host }}</a>
|
|
47
49
|
{%- else %} <a class="u-url" href="{{ url }}">a page on {{ url | host }}</a>
|
|
@@ -87,6 +87,16 @@
|
|
|
87
87
|
<p class="comment-signed-in">
|
|
88
88
|
Commenting as <a href="{{ commentForm.signedInAs.url }}">{{ commentForm.signedInAs.name }}</a>.
|
|
89
89
|
</p>
|
|
90
|
+
|
|
91
|
+
{#
|
|
92
|
+
What is posted here is a reply post (TASK-300). Unticked it is Unlisted:
|
|
93
|
+
its own page and the thread, and no listing or feed. Ticked it is Public.
|
|
94
|
+
It reaches whoever it answers either way.
|
|
95
|
+
#}
|
|
96
|
+
<p class="comment-check">
|
|
97
|
+
<input id="comment-listed" name="{{ commentForm.fields.listed }}" type="checkbox" value="1"{% if commentForm.values.listed %} checked{% endif %} />
|
|
98
|
+
<label for="comment-listed">Include in posts and feeds</label>
|
|
99
|
+
</p>
|
|
90
100
|
{% else %}
|
|
91
101
|
{#
|
|
92
102
|
When this form was drawn, which is what the minimum submit time is
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{#
|
|
2
|
+
One reply and everything under it. A macro rather than an include so it can
|
|
3
|
+
call itself: a reply that answers a reply is the same thing one level in.
|
|
4
|
+
|
|
5
|
+
`classes` is the reply's microformat. Under a post each reply is an
|
|
6
|
+
`h-entry` of its own. On a comment's own page (TASK-318) the comment is the
|
|
7
|
+
page's one entry, so its replies are `p-comment h-cite` inside it.
|
|
8
|
+
|
|
9
|
+
A `withheld` entry (TASK-325) is a comment a reader may not see that has
|
|
10
|
+
visible replies under it. It keeps its anchor and prints `withheld()` in
|
|
11
|
+
place of an author and words, as a comment's own page does for an ancestor,
|
|
12
|
+
and is no microformat of its own.
|
|
13
|
+
#}
|
|
14
|
+
{% macro withheld() %}This comment is no longer shown.{% endmacro %}
|
|
15
|
+
|
|
16
|
+
{% macro comment(reply, classes="h-entry") %}
|
|
17
|
+
{% if reply.withheld %}
|
|
18
|
+
<li id="comment-{{ reply.id }}" class="comment comment-placeholder">
|
|
19
|
+
<p class="comment-withheld">{{ withheld() }}</p>
|
|
20
|
+
<ol class="children">
|
|
21
|
+
{% for child in reply.replies %}
|
|
22
|
+
{{ comment(child, classes) }}
|
|
23
|
+
{% endfor %}
|
|
24
|
+
</ol>
|
|
25
|
+
</li>
|
|
26
|
+
{% else %}
|
|
27
|
+
<li id="comment-{{ reply.id }}" class="comment {{ classes }} comment-{{ reply.source }}">
|
|
28
|
+
<article class="comment-body">
|
|
29
|
+
<footer class="comment-meta">
|
|
30
|
+
<div class="comment-author vcard p-author h-card">
|
|
31
|
+
{%- if reply.author.avatar %}
|
|
32
|
+
<img class="avatar u-photo" src="{{ reply.author.avatar }}" alt="" width="40" height="40" loading="lazy">
|
|
33
|
+
{%- else %}
|
|
34
|
+
<span class="comment-avatar-empty" aria-hidden="true">{{ reply.author.name | first | upper }}</span>
|
|
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>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="comment-metadata">
|
|
39
|
+
{%- if reply.url %}
|
|
40
|
+
<a class="u-url" href="{{ reply.url }}"{% if reply.source != "comment" and reply.source != "post" %} rel="nofollow noopener noreferrer"{% endif %}><time class="dt-published" datetime="{{ reply.published | date("iso") }}">{{ reply.published | date }}</time></a>
|
|
41
|
+
{%- else %}
|
|
42
|
+
<time class="dt-published" datetime="{{ reply.published | date("iso") }}">{{ reply.published | date }}</time>
|
|
43
|
+
{%- endif %}
|
|
44
|
+
{%- if reply.source == "webmention" %}
|
|
45
|
+
<span class="comment-source">via webmention</span>
|
|
46
|
+
{%- elif reply.source == "activitypub" %}
|
|
47
|
+
<span class="comment-source">via the fediverse</span>
|
|
48
|
+
{%- endif %}
|
|
49
|
+
</div>
|
|
50
|
+
</footer>
|
|
51
|
+
<div class="comment-content e-content">
|
|
52
|
+
{%- if reply.rsvp %}
|
|
53
|
+
<p class="comment-rsvp"><data class="p-rsvp" value="{{ reply.rsvp.value }}">{{ reply.rsvp.label }}</data></p>
|
|
54
|
+
{%- endif %}
|
|
55
|
+
{{ reply.content | safe }}
|
|
56
|
+
</div>
|
|
57
|
+
{#
|
|
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
|
|
60
|
+
signed in can answer anything in the thread, and their answer is a reply
|
|
61
|
+
post that reaches a webmention's page or a fediverse reply's author
|
|
62
|
+
(TASK-300). A visitor answers comments written here only: a fediverse
|
|
63
|
+
reply is answered on the server that holds it, and a webmention on the
|
|
64
|
+
page that sent it.
|
|
65
|
+
#}
|
|
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>
|
|
68
|
+
{% endif %}
|
|
69
|
+
</article>
|
|
70
|
+
{% if reply.replies.length %}
|
|
71
|
+
<ol class="children">
|
|
72
|
+
{% for child in reply.replies %}
|
|
73
|
+
{{ comment(child, classes) }}
|
|
74
|
+
{% endfor %}
|
|
75
|
+
</ol>
|
|
76
|
+
{% endif %}
|
|
77
|
+
</li>
|
|
78
|
+
{% endif %}
|
|
79
|
+
{% endmacro %}
|
|
@@ -11,9 +11,16 @@
|
|
|
11
11
|
the shape it is handed is documented in the theme README under "The
|
|
12
12
|
conversation".
|
|
13
13
|
|
|
14
|
+
`conversationPart` is `reactions` or `replies` for one half of it, which is
|
|
15
|
+
how a reply post prints its replies inside its entry (TASK-320), and the
|
|
16
|
+
whole of it otherwise.
|
|
17
|
+
|
|
14
18
|
The macros come first because Nunjucks defines one where it stands rather
|
|
15
|
-
than hoisting it, and the two sections below call them.
|
|
19
|
+
than hoisting it, and the two sections below call them. One reply and
|
|
20
|
+
everything under it is `partials/comment.njk`, which a comment's own page
|
|
21
|
+
prints its replies with too.
|
|
16
22
|
#}
|
|
23
|
+
{% import "partials/comment.njk" as thread with context %}
|
|
17
24
|
{#
|
|
18
25
|
One face in a facepile: somebody's avatar, linked to wherever they are.
|
|
19
26
|
|
|
@@ -52,60 +59,6 @@
|
|
|
52
59
|
{% endif %}
|
|
53
60
|
{% endmacro %}
|
|
54
61
|
|
|
55
|
-
{#
|
|
56
|
-
One reply and everything under it. A macro rather than an include so it can
|
|
57
|
-
call itself: a reply that answers a reply is the same thing one level in.
|
|
58
|
-
#}
|
|
59
|
-
{% macro comment(reply) %}
|
|
60
|
-
<li id="comment-{{ reply.id }}" class="comment h-entry comment-{{ reply.source }}">
|
|
61
|
-
<article class="comment-body">
|
|
62
|
-
<footer class="comment-meta">
|
|
63
|
-
<div class="comment-author vcard p-author h-card">
|
|
64
|
-
{%- if reply.author.avatar %}
|
|
65
|
-
<img class="avatar u-photo" src="{{ reply.author.avatar }}" alt="" width="40" height="40" loading="lazy">
|
|
66
|
-
{%- else %}
|
|
67
|
-
<span class="comment-avatar-empty" aria-hidden="true">{{ reply.author.name | first | upper }}</span>
|
|
68
|
-
{%- endif %}
|
|
69
|
-
<b class="fn p-name">{% if reply.author.url %}<a class="url u-url" href="{{ reply.author.url }}" rel="nofollow ugc noopener noreferrer">{{ reply.author.name }}</a>{% else %}{{ reply.author.name }}{% endif %}</b>
|
|
70
|
-
</div>
|
|
71
|
-
<div class="comment-metadata">
|
|
72
|
-
{%- if reply.url %}
|
|
73
|
-
<a class="u-url" href="{{ reply.url }}"{% if reply.source != "comment" %} rel="nofollow noopener noreferrer"{% endif %}><time class="dt-published" datetime="{{ reply.published | date("iso") }}">{{ reply.published | date }}</time></a>
|
|
74
|
-
{%- else %}
|
|
75
|
-
<time class="dt-published" datetime="{{ reply.published | date("iso") }}">{{ reply.published | date }}</time>
|
|
76
|
-
{%- endif %}
|
|
77
|
-
{%- if reply.source == "webmention" %}
|
|
78
|
-
<span class="comment-source">via webmention</span>
|
|
79
|
-
{%- elif reply.source == "activitypub" %}
|
|
80
|
-
<span class="comment-source">via the fediverse</span>
|
|
81
|
-
{%- endif %}
|
|
82
|
-
</div>
|
|
83
|
-
</footer>
|
|
84
|
-
<div class="comment-content e-content">
|
|
85
|
-
{%- if reply.rsvp %}
|
|
86
|
-
<p class="comment-rsvp"><data class="p-rsvp" value="{{ reply.rsvp.value }}">{{ reply.rsvp.label }}</data></p>
|
|
87
|
-
{%- endif %}
|
|
88
|
-
{{ reply.content | safe }}
|
|
89
|
-
</div>
|
|
90
|
-
{#
|
|
91
|
-
Answering a comment on this site needs no JavaScript: the link carries
|
|
92
|
-
the comment's id to the form, which puts it in a hidden field. A
|
|
93
|
-
fediverse reply is answered on the server that holds it, and a webmention
|
|
94
|
-
is answered on the page that sent it, so neither gets such a link.
|
|
95
|
-
#}
|
|
96
|
-
{% if commentForm and reply.source == "comment" %}
|
|
97
|
-
<div class="reply"><a class="comment-reply-link" href="{{ page.url }}?reply_to={{ reply.id | urlencode }}#respond">Reply</a></div>
|
|
98
|
-
{% endif %}
|
|
99
|
-
</article>
|
|
100
|
-
{% if reply.replies.length %}
|
|
101
|
-
<ol class="children">
|
|
102
|
-
{% for child in reply.replies %}
|
|
103
|
-
{{ comment(child) }}
|
|
104
|
-
{% endfor %}
|
|
105
|
-
</ol>
|
|
106
|
-
{% endif %}
|
|
107
|
-
</li>
|
|
108
|
-
{% endmacro %}
|
|
109
62
|
|
|
110
63
|
{#
|
|
111
64
|
Who is coming to an event (TASK-200): each answer it was given, by a
|
|
@@ -114,7 +67,9 @@
|
|
|
114
67
|
first. A post that is no event has no groups.
|
|
115
68
|
#}
|
|
116
69
|
{% set rsvpIcons = { yes: "✅", maybe: "🤔", interested: "⭐", no: "❌" } %}
|
|
117
|
-
{%
|
|
70
|
+
{% set showReactions = conversationPart != "replies" %}
|
|
71
|
+
{% set showReplies = conversationPart != "reactions" %}
|
|
72
|
+
{% if showReactions and conversation.rsvps.length %}
|
|
118
73
|
<div class="reactions-section rsvps-section">
|
|
119
74
|
{%- for answer in conversation.rsvps %}
|
|
120
75
|
{{- group(answer.people, answer.label, "rsvp-" + answer.value, rsvpIcons[answer.value]) }}
|
|
@@ -128,7 +83,7 @@
|
|
|
128
83
|
boosts, which is why there are three groups and not four. `p-like`,
|
|
129
84
|
`p-repost` and `p-mention` are the source theme's classes for them.
|
|
130
85
|
#}
|
|
131
|
-
{% if conversation.likes.length or conversation.boosts.length or conversation.mentions.length %}
|
|
86
|
+
{% if showReactions and (conversation.likes.length or conversation.boosts.length or conversation.mentions.length) %}
|
|
132
87
|
<div class="reactions-section">
|
|
133
88
|
{{- group(conversation.likes, "Likes", "p-like", "❤️") }}
|
|
134
89
|
{{- group(conversation.boosts, "Boosts", "p-repost", "🔁") }}
|
|
@@ -150,7 +105,7 @@
|
|
|
150
105
|
switch, the closing window and the post's own front matter all agree it is
|
|
151
106
|
open, so there is nothing else for a theme to work out.
|
|
152
107
|
#}
|
|
153
|
-
{% if conversation.replies.length %}
|
|
108
|
+
{% if showReplies and conversation.replies.length %}
|
|
154
109
|
<div id="comments" class="comments-area">
|
|
155
110
|
<h2 class="comments-title">
|
|
156
111
|
{{- conversation.counts.replies | plural({ one: "One reply", other: "# replies" }, "en") -}}
|
|
@@ -158,7 +113,7 @@
|
|
|
158
113
|
|
|
159
114
|
<ol class="comment-list">
|
|
160
115
|
{% for reply in conversation.replies %}
|
|
161
|
-
{{ comment(reply) }}
|
|
116
|
+
{{ thread.comment(reply, "p-comment h-cite" if conversationPart == "replies" else "h-entry") }}
|
|
162
117
|
{% endfor %}
|
|
163
118
|
</ol>
|
|
164
119
|
|
|
@@ -873,6 +873,26 @@
|
|
|
873
873
|
@apply target;
|
|
874
874
|
}
|
|
875
875
|
|
|
876
|
+
.backlinks {
|
|
877
|
+
@apply mt-12 font-sans text-sm;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.backlinks-title {
|
|
881
|
+
@apply mb-2 text-[0.72rem] font-normal tracking-[0.14em] text-muted uppercase;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
.backlinks ol {
|
|
885
|
+
@apply list-none space-y-1 p-0;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
.backlinks a {
|
|
889
|
+
@apply target;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
.backlinks time {
|
|
893
|
+
@apply ms-1 text-muted;
|
|
894
|
+
}
|
|
895
|
+
|
|
876
896
|
/* Pagination: two words, the newer at the start and the older at the end. */
|
|
877
897
|
.pagination {
|
|
878
898
|
@apply mt-12 flex flex-wrap gap-4 font-sans text-sm;
|
|
@@ -1027,6 +1047,28 @@
|
|
|
1027
1047
|
@apply mt-8 font-sans text-sm text-muted italic;
|
|
1028
1048
|
}
|
|
1029
1049
|
|
|
1050
|
+
/* A comment's own page (TASK-318): the thread above it as one citation,
|
|
1051
|
+
each step drawn flat although each is nested in the next. */
|
|
1052
|
+
.comment-thread {
|
|
1053
|
+
@apply mb-8;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
.comment-step > .comment-step {
|
|
1057
|
+
@apply mb-4;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
.comment-withheld {
|
|
1061
|
+
@apply italic;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
.comment-page .comments-area {
|
|
1065
|
+
@apply mt-10;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
.comment-back {
|
|
1069
|
+
@apply mt-10 font-sans text-sm;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1030
1072
|
/* The comment form under an open post and the contact form on a page that
|
|
1031
1073
|
asked for one, which wears the same class. */
|
|
1032
1074
|
.comment-respond {
|
|
@@ -1619,6 +1619,50 @@
|
|
|
1619
1619
|
display: inline-flex;
|
|
1620
1620
|
}
|
|
1621
1621
|
|
|
1622
|
+
.backlinks {
|
|
1623
|
+
margin-top: calc(var(--spacing) * 12);
|
|
1624
|
+
font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
1625
|
+
font-size: var(--text-sm);
|
|
1626
|
+
line-height: var(--tw-leading, var(--text-sm--line-height));
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
.backlinks-title {
|
|
1630
|
+
margin-bottom: calc(var(--spacing) * 2);
|
|
1631
|
+
--tw-font-weight: var(--font-weight-normal);
|
|
1632
|
+
font-size: .72rem;
|
|
1633
|
+
font-weight: var(--font-weight-normal);
|
|
1634
|
+
--tw-tracking: .14em;
|
|
1635
|
+
letter-spacing: .14em;
|
|
1636
|
+
color: var(--color-muted);
|
|
1637
|
+
text-transform: uppercase;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
.backlinks ol {
|
|
1641
|
+
list-style-type: none;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
:where(.backlinks ol > :not(:last-child)) {
|
|
1645
|
+
--tw-space-y-reverse: 0;
|
|
1646
|
+
margin-block-start: calc(var(--spacing) * var(--tw-space-y-reverse));
|
|
1647
|
+
margin-block-end: calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)));
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
.backlinks ol {
|
|
1651
|
+
padding: 0;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
.backlinks a {
|
|
1655
|
+
align-items: center;
|
|
1656
|
+
min-block-size: 24px;
|
|
1657
|
+
min-inline-size: 24px;
|
|
1658
|
+
display: inline-flex;
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
.backlinks time {
|
|
1662
|
+
color: var(--color-muted);
|
|
1663
|
+
margin-inline-start: var(--spacing);
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1622
1666
|
.pagination {
|
|
1623
1667
|
margin-top: calc(var(--spacing) * 12);
|
|
1624
1668
|
gap: calc(var(--spacing) * 4);
|
|
@@ -2028,6 +2072,29 @@
|
|
|
2028
2072
|
font-style: italic;
|
|
2029
2073
|
}
|
|
2030
2074
|
|
|
2075
|
+
.comment-thread {
|
|
2076
|
+
margin-bottom: calc(var(--spacing) * 8);
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
.comment-step > .comment-step {
|
|
2080
|
+
margin-bottom: calc(var(--spacing) * 4);
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
.comment-withheld {
|
|
2084
|
+
font-style: italic;
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
.comment-page .comments-area {
|
|
2088
|
+
margin-top: calc(var(--spacing) * 10);
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
.comment-back {
|
|
2092
|
+
margin-top: calc(var(--spacing) * 10);
|
|
2093
|
+
font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
2094
|
+
font-size: var(--text-sm);
|
|
2095
|
+
line-height: var(--tw-leading, var(--text-sm--line-height));
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2031
2098
|
.comment-respond {
|
|
2032
2099
|
margin-top: calc(var(--spacing) * 12);
|
|
2033
2100
|
border-top-style: var(--tw-border-style);
|