@geekity/cms 0.22.0 → 0.24.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 +19 -4
- package/admin/pages/documents/editor.njk +18 -0
- package/admin/static/editor.js +1 -1
- package/dist/admin/comments.js +2 -2
- package/dist/admin/comments.js.map +1 -1
- package/dist/admin/documents.d.ts +36 -7
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +140 -29
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/editor-layout.d.ts +1 -1
- package/dist/admin/editor-layout.d.ts.map +1 -1
- package/dist/admin/editor-layout.js +6 -1
- package/dist/admin/editor-layout.js.map +1 -1
- package/dist/admin/event-field.d.ts +26 -0
- package/dist/admin/event-field.d.ts.map +1 -0
- package/dist/admin/event-field.js +74 -0
- package/dist/admin/event-field.js.map +1 -0
- package/dist/admin/federation.js +3 -3
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/media.js +2 -2
- package/dist/admin/media.js.map +1 -1
- package/dist/admin/preview.d.ts.map +1 -1
- package/dist/admin/preview.js +16 -1
- package/dist/admin/preview.js.map +1 -1
- package/dist/admin/store.d.ts +9 -0
- package/dist/admin/store.d.ts.map +1 -1
- package/dist/admin/store.js +16 -5
- package/dist/admin/store.js.map +1 -1
- package/dist/avatars/avatars.js +1 -1
- package/dist/avatars/avatars.js.map +1 -1
- package/dist/comments/policy.d.ts +10 -0
- package/dist/comments/policy.d.ts.map +1 -1
- package/dist/comments/policy.js +12 -0
- package/dist/comments/policy.js.map +1 -1
- package/dist/comments/records.d.ts +5 -1
- package/dist/comments/records.d.ts.map +1 -1
- package/dist/comments/records.js +16 -2
- package/dist/comments/records.js.map +1 -1
- package/dist/content/event.d.ts +40 -0
- package/dist/content/event.d.ts.map +1 -0
- package/dist/content/event.js +51 -0
- package/dist/content/event.js.map +1 -0
- package/dist/content/handles.d.ts +22 -0
- package/dist/content/handles.d.ts.map +1 -0
- package/dist/content/handles.js +68 -0
- package/dist/content/handles.js.map +1 -0
- package/dist/content/markdown.d.ts +8 -2
- package/dist/content/markdown.d.ts.map +1 -1
- package/dist/content/markdown.js +55 -5
- package/dist/content/markdown.js.map +1 -1
- package/dist/content/parser.d.ts +3 -0
- package/dist/content/parser.d.ts.map +1 -1
- package/dist/content/parser.js +1 -1
- package/dist/content/parser.js.map +1 -1
- package/dist/content/post-type.d.ts +12 -8
- package/dist/content/post-type.d.ts.map +1 -1
- package/dist/content/post-type.js +12 -2
- package/dist/content/post-type.js.map +1 -1
- package/dist/content/rsvp.d.ts +29 -0
- package/dist/content/rsvp.d.ts.map +1 -0
- package/dist/content/rsvp.js +49 -0
- package/dist/content/rsvp.js.map +1 -0
- package/dist/content/save.d.ts +2 -1
- package/dist/content/save.d.ts.map +1 -1
- package/dist/content/save.js +10 -3
- package/dist/content/save.js.map +1 -1
- package/dist/content/store.d.ts +11 -4
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js +15 -4
- package/dist/content/store.js.map +1 -1
- package/dist/content/sync.d.ts.map +1 -1
- package/dist/content/sync.js +7 -6
- package/dist/content/sync.js.map +1 -1
- package/dist/env.d.ts +3 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/federation/article.d.ts +9 -3
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +90 -34
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/cited-post.d.ts +13 -0
- package/dist/federation/cited-post.d.ts.map +1 -0
- package/dist/federation/cited-post.js +75 -0
- package/dist/federation/cited-post.js.map +1 -0
- package/dist/federation/delivery.d.ts.map +1 -1
- package/dist/federation/delivery.js +31 -2
- package/dist/federation/delivery.js.map +1 -1
- package/dist/federation/handles.d.ts +28 -0
- package/dist/federation/handles.d.ts.map +1 -0
- package/dist/federation/handles.js +65 -0
- package/dist/federation/handles.js.map +1 -0
- package/dist/federation/inbox.d.ts +2 -1
- package/dist/federation/inbox.d.ts.map +1 -1
- package/dist/federation/inbox.js +11 -3
- package/dist/federation/inbox.js.map +1 -1
- package/dist/federation/mount.d.ts.map +1 -1
- package/dist/federation/mount.js +18 -2
- package/dist/federation/mount.js.map +1 -1
- package/dist/federation/profiles.d.ts.map +1 -1
- package/dist/federation/profiles.js +2 -8
- package/dist/federation/profiles.js.map +1 -1
- package/dist/federation/site-loaders.d.ts +15 -0
- package/dist/federation/site-loaders.d.ts.map +1 -0
- package/dist/federation/site-loaders.js +19 -0
- package/dist/federation/site-loaders.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -1
- package/dist/indieauth/client.js +2 -2
- package/dist/indieauth/client.js.map +1 -1
- package/dist/micropub/create.d.ts +2 -1
- package/dist/micropub/create.d.ts.map +1 -1
- package/dist/micropub/create.js +57 -8
- package/dist/micropub/create.js.map +1 -1
- package/dist/micropub/endpoint.d.ts.map +1 -1
- package/dist/micropub/endpoint.js +12 -4
- package/dist/micropub/endpoint.js.map +1 -1
- package/dist/micropub/update.d.ts +3 -0
- package/dist/micropub/update.d.ts.map +1 -1
- package/dist/micropub/update.js +29 -4
- package/dist/micropub/update.js.map +1 -1
- package/dist/web/context.d.ts +32 -4
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +28 -1
- package/dist/web/context.js.map +1 -1
- package/dist/web/conversation.d.ts +26 -1
- package/dist/web/conversation.d.ts.map +1 -1
- package/dist/web/conversation.js +67 -10
- package/dist/web/conversation.js.map +1 -1
- package/dist/web/documents.d.ts +12 -0
- package/dist/web/documents.d.ts.map +1 -1
- package/dist/web/documents.js +20 -0
- package/dist/web/documents.js.map +1 -1
- package/dist/web/errors.d.ts.map +1 -1
- package/dist/web/errors.js +5 -3
- package/dist/web/errors.js.map +1 -1
- package/dist/web/feed-item.d.ts.map +1 -1
- package/dist/web/feed-item.js +8 -3
- package/dist/web/feed-item.js.map +1 -1
- package/dist/web/llms.d.ts +8 -0
- package/dist/web/llms.d.ts.map +1 -1
- package/dist/web/llms.js +25 -7
- package/dist/web/llms.js.map +1 -1
- package/dist/web/maintenance.d.ts.map +1 -1
- package/dist/web/maintenance.js +5 -2
- package/dist/web/maintenance.js.map +1 -1
- package/dist/web/negotiate.d.ts +4 -2
- package/dist/web/negotiate.d.ts.map +1 -1
- package/dist/web/negotiate.js +17 -7
- package/dist/web/negotiate.js.map +1 -1
- package/dist/web/render.d.ts +3 -0
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +39 -6
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +67 -25
- package/dist/web/routes.js.map +1 -1
- package/dist/web/templates.d.ts +4 -1
- package/dist/web/templates.d.ts.map +1 -1
- package/dist/web/templates.js +11 -0
- package/dist/web/templates.js.map +1 -1
- package/dist/webmention/cited-picture.d.ts +11 -4
- package/dist/webmention/cited-picture.d.ts.map +1 -1
- package/dist/webmention/cited-picture.js +22 -13
- package/dist/webmention/cited-picture.js.map +1 -1
- package/dist/webmention/cited-start.d.ts +10 -0
- package/dist/webmention/cited-start.d.ts.map +1 -0
- package/dist/webmention/cited-start.js +21 -0
- package/dist/webmention/cited-start.js.map +1 -0
- package/dist/webmention/fetch-public.d.ts +2 -2
- package/dist/webmention/fetch-public.d.ts.map +1 -1
- package/dist/webmention/fetch-public.js +1 -1
- package/dist/webmention/fetch-public.js.map +1 -1
- package/dist/webmention/html.d.ts +2 -0
- package/dist/webmention/html.d.ts.map +1 -1
- package/dist/webmention/html.js +6 -0
- package/dist/webmention/html.js.map +1 -1
- package/dist/webmention/index.d.ts +2 -1
- 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/microformats.d.ts +25 -2
- package/dist/webmention/microformats.d.ts.map +1 -1
- package/dist/webmention/microformats.js +38 -4
- package/dist/webmention/microformats.js.map +1 -1
- package/dist/webmention/pingback.d.ts +42 -0
- package/dist/webmention/pingback.d.ts.map +1 -0
- package/dist/webmention/pingback.js +229 -0
- package/dist/webmention/pingback.js.map +1 -0
- package/dist/webmention/receive.d.ts +20 -2
- package/dist/webmention/receive.d.ts.map +1 -1
- package/dist/webmention/receive.js +25 -16
- package/dist/webmention/receive.js.map +1 -1
- package/dist/webmention/reply-context.d.ts +65 -18
- package/dist/webmention/reply-context.d.ts.map +1 -1
- package/dist/webmention/reply-context.js +403 -99
- package/dist/webmention/reply-context.js.map +1 -1
- package/dist/webmention/reply-contexts.d.ts +3 -1
- package/dist/webmention/reply-contexts.d.ts.map +1 -1
- package/dist/webmention/reply-contexts.js +53 -17
- package/dist/webmention/reply-contexts.js.map +1 -1
- package/dist/webmention/routes.d.ts.map +1 -1
- package/dist/webmention/routes.js +2 -0
- package/dist/webmention/routes.js.map +1 -1
- package/dist/webmention/service.d.ts +11 -0
- package/dist/webmention/service.d.ts.map +1 -1
- package/dist/webmention/service.js +27 -6
- package/dist/webmention/service.js.map +1 -1
- package/dist/webmention/syndication.d.ts +6 -0
- package/dist/webmention/syndication.d.ts.map +1 -1
- package/dist/webmention/syndication.js +12 -0
- package/dist/webmention/syndication.js.map +1 -1
- package/package.json +7 -7
- package/themes/default/README.md +127 -37
- package/themes/default/layouts/410.njk +10 -0
- package/themes/default/layouts/base.njk +3 -0
- package/themes/default/layouts/page.njk +7 -0
- package/themes/default/layouts/post.njk +7 -4
- package/themes/default/layouts/search.njk +1 -1
- package/themes/default/partials/cited-page.njk +7 -0
- package/themes/default/partials/conversation.njk +25 -5
- package/themes/default/partials/event.njk +27 -0
- package/themes/default/partials/jsonld.njk +28 -0
- package/themes/default/partials/post-list.njk +5 -2
- package/themes/default/partials/reply-context.njk +24 -4
- package/themes/default/partials/rsvp.njk +7 -0
- package/themes/default/src/style.css +20 -0
- package/themes/default/static/style.css +35 -0
package/themes/default/README.md
CHANGED
|
@@ -17,6 +17,7 @@ themes/default/
|
|
|
17
17
|
author.njk one person's archive, paginated
|
|
18
18
|
search.njk the search form and what it found, paginated
|
|
19
19
|
404.njk nothing at this URL
|
|
20
|
+
410.njk what was at this URL was deleted
|
|
20
21
|
500.njk the request failed on the server
|
|
21
22
|
503.njk the site is in maintenance mode
|
|
22
23
|
partials/
|
|
@@ -25,14 +26,15 @@ themes/default/
|
|
|
25
26
|
tags.njk macros for tag and category links
|
|
26
27
|
kicker.njk the line above an entry naming its kind and date
|
|
27
28
|
reply-context.njk the citation of what a reply answers
|
|
29
|
+
event.njk when and where an event is
|
|
28
30
|
citations.njk the citation of what a like, repost or bookmark cites
|
|
29
31
|
cited-page.njk the name and author both citations print
|
|
30
32
|
read.njk what a read post read, and how far
|
|
31
33
|
bio.njk who an entry is by, as an h-card
|
|
32
34
|
menu.njk one named menu, as a nav of links
|
|
33
35
|
feeds.njk macros for the feed links in <head>
|
|
34
|
-
conversation.njk the replies, likes and boosts under a post
|
|
35
|
-
comment-form.njk the form under a post that is taking comments
|
|
36
|
+
conversation.njk the replies, likes and boosts under a post or an open page
|
|
37
|
+
comment-form.njk the form under a post or page that is taking comments
|
|
36
38
|
contact-form.njk the form on a page whose front matter says contact: true
|
|
37
39
|
archive.njk every post by month, on a page that says archive: true
|
|
38
40
|
search-form.njk the search box, on the search page
|
|
@@ -418,6 +420,44 @@ title and summary. The same partial cites a reply in a feed. The layouts own
|
|
|
418
420
|
the placement; the partial owns only what the citation says, and it stays
|
|
419
421
|
inside the `h-entry` wherever it is printed.
|
|
420
422
|
|
|
423
|
+
**A reply to a silo copy cites the original** (TASK-197). When the post a
|
|
424
|
+
reply answers is a copy of a post on another site, and that post lists the
|
|
425
|
+
copy as its `u-syndication`, `replyContext.original` is the original's URL and
|
|
426
|
+
the rest of `replyContext` describes the original. The `h-cite` links the
|
|
427
|
+
original, and a `p.cite-copy` after it says "Also in reply to its copy on" the
|
|
428
|
+
silo's host, linking the copy as a `u-in-reply-to` of its own, so a parser
|
|
429
|
+
reads both as what the post answers.
|
|
430
|
+
|
|
431
|
+
**An RSVP says whether its author is going** (TASK-198). An RSVP is a reply
|
|
432
|
+
to an event whose `rsvp` is `yes`, `no`, `maybe` or `interested`.
|
|
433
|
+
`partials/rsvp.njk` opens its `e-content` with a `p.rsvp-line` holding a
|
|
434
|
+
`data.p-rsvp` whose value is the answer and whose text is Going, Not going,
|
|
435
|
+
Maybe or Interested; it prints `rsvp.line`, the HTML the feeds also carry. Its
|
|
436
|
+
reply context says "RSVP to" rather than "In reply to", and when the event's
|
|
437
|
+
page is an `h-event`, or describes a schema.org `Event` in JSON-LD, its start
|
|
438
|
+
follows the event's name as a `time.dt-start` and its place as a
|
|
439
|
+
`span.p-location`, inside the `h-cite`. A start the event page wrote with no
|
|
440
|
+
zone is that wall clock where the event is, so it is printed in UTC
|
|
441
|
+
(`replyContext.startZone`) rather than moved into the site's zone. Its kicker
|
|
442
|
+
and its hidden `h1` say RSVP. An RSVP to a silo copy of an event cites the
|
|
443
|
+
original as a reply does.
|
|
444
|
+
|
|
445
|
+
**An event is an h-event** (TASK-200, decision-32). A post whose front matter
|
|
446
|
+
has a readable `start` is an event: its title is the event's name, its body
|
|
447
|
+
the description, and `end` and `location` are optional. `layouts/post.njk`
|
|
448
|
+
types its article `h-event` rather than `h-entry`, its kicker and hidden `h1`
|
|
449
|
+
say Event, and `partials/event.njk` follows the title with a
|
|
450
|
+
`dl.event-details`. The When row is a `time.dt-start` and, with an end, a
|
|
451
|
+
`time.dt-end`, each written with the `date` filter's `datetime` format in the
|
|
452
|
+
site's zone, with the instant as its `datetime`. The Where row is a
|
|
453
|
+
`span.p-location` holding the place's words, or "Online at" an
|
|
454
|
+
`a.p-location` that links the address to join an online event. The JSON-LD
|
|
455
|
+
describes the post as a schema.org `Event` instead of a `BlogPosting`. That
|
|
456
|
+
`Event` is a `Place` or a `VirtualLocation`, carries an attendance mode and an
|
|
457
|
+
`EventScheduled` status, and names the author's Person as its `organizer`.
|
|
458
|
+
The answers it is given are grouped in `conversation.rsvps`; see [The
|
|
459
|
+
conversation](#the-conversation).
|
|
460
|
+
|
|
421
461
|
**A like, a repost or a bookmark cites what it cites** (TASK-169) with
|
|
422
462
|
`partials/citations.njk`, beside the reply context and drawn the same way: one
|
|
423
463
|
`div.reply-context.cite.h-cite` per entry of `citations`, classed
|
|
@@ -452,6 +492,21 @@ bookmark of a Scripting News post reads "Bookmarked RSS tip #2 · Scripting
|
|
|
452
492
|
News". A like's, a repost's or a bookmark's citation never prints the page's
|
|
453
493
|
description, which on many sites describes the site rather than the post.
|
|
454
494
|
|
|
495
|
+
**A citation shows who wrote the cited page** (TASK-199) as fully as the page
|
|
496
|
+
said. The author's photo, an `img.u-photo.cite-avatar` with empty alt text
|
|
497
|
+
since their name is beside it, comes before the name inside the `h-card`; a
|
|
498
|
+
fediverse author's handle follows the name as a `span.p-nickname.cite-handle`
|
|
499
|
+
reading `@user@host`. The photo is the `u-photo` of the `h-entry` author's
|
|
500
|
+
`h-card` (or of the page's `h-card` for the same person), the avatar of the
|
|
501
|
+
account an ActivityPub object is attributed to, or the author image in the
|
|
502
|
+
page's JSON-LD, copied into the site's uploads as a picture is, and left out
|
|
503
|
+
when the post has removed its preview. A Mastodon status is read from the
|
|
504
|
+
ActivityPub object its page links, so its author's display name, handle,
|
|
505
|
+
avatar, words, first image and date come from the status itself rather than
|
|
506
|
+
from the page's `og:title`. A page with no `h-entry` and no object is read
|
|
507
|
+
from its JSON-LD (`headline`, `author`, `datePublished`, `image`) and then its
|
|
508
|
+
Open Graph, Twitter and `article:` tags.
|
|
509
|
+
|
|
455
510
|
**A citation shows the cited page's picture** (TASK-252) when the page named
|
|
456
511
|
one and the post has not removed its preview. The picture is the page's
|
|
457
512
|
oEmbed photo, else its oEmbed thumbnail, else its `og:image`, else its
|
|
@@ -553,8 +608,9 @@ its front matter names no `image`.
|
|
|
553
608
|
After the entry a post prints `nav.blog-post-nav`: the `previous` and `next`
|
|
554
609
|
posts as two cards, `rel="prev"` and `rel="next"`, each opening on a
|
|
555
610
|
`span.blog-post-nav-label`, and nothing at all at the ends of the archive; then
|
|
556
|
-
the conversation and the comment form. A page prints the
|
|
557
|
-
|
|
611
|
+
the conversation and the comment form. A page prints the conversation and the
|
|
612
|
+
comment form too when it takes comments, and the contact form when its front
|
|
613
|
+
matter asked for one. A page has no neighbours, no tags and no
|
|
558
614
|
syndication links, because none of those are things a page has.
|
|
559
615
|
|
|
560
616
|
### The bio
|
|
@@ -724,6 +780,13 @@ writes one today and the header is the heading alone.
|
|
|
724
780
|
links home and to the search. The 500 and 503 pages below open on a kicker the
|
|
725
781
|
same way.
|
|
726
782
|
|
|
783
|
+
`layouts/410.njk` is the page at the URL of a post or page that was moved to
|
|
784
|
+
the trash (TASK-195). It says `This content has been deleted.` under a
|
|
785
|
+
`Deleted` kicker and links home and to the search. The context is the 404's:
|
|
786
|
+
`title`, `url` and `page.url`, and nothing of the deleted document. Its `.md`
|
|
787
|
+
and `.json` representations answer 410 too. A trashed draft was never public,
|
|
788
|
+
so its URL is a 404 instead.
|
|
789
|
+
|
|
727
790
|
`layouts/500.njk` is the page a request gets when the server fails while
|
|
728
791
|
answering it (TASK-129). It says `Something went wrong.` in an
|
|
729
792
|
`article.server-error` and links home. The context is the 404's: `title`,
|
|
@@ -1261,6 +1324,8 @@ A document — one post, one page, or one entry of a listing — adds:
|
|
|
1261
1324
|
| `photos` | The post's photos, each `{ url, alt, html }`; `html` is the `img.u-photo`, responsive. Empty with none. |
|
|
1262
1325
|
| `citations` | What it reposts, likes or bookmarks, each `{ property, url, context }`; `context` as `replyContext`, when known. |
|
|
1263
1326
|
| `read` | A read post's `{ status, statusLabel, of, line }`; `of` is `{ name, author, uid, uidLabel, url }`. |
|
|
1327
|
+
| `rsvp` | An RSVP's `{ value, label, line }`: `yes`, `no`, `maybe` or `interested`, its words, and its `p-rsvp` line. |
|
|
1328
|
+
| `event` | An event's `{ start, end, location }`: `Date`s, and `{ kind: "place", name }` or `{ kind: "virtual", url }`. |
|
|
1264
1329
|
| `syndicateTo` | On a post's page, the syndication targets it selects, each `{ id, name, url }`. Empty with none. |
|
|
1265
1330
|
| `syndication` | Its copies elsewhere, each `{ url, label }`: front matter `syndication`, and on its page the copies targets made. |
|
|
1266
1331
|
| `author` | Who wrote it, as a profile rather than a string. See [Bylines and author archives](#bylines-and-author-archives). |
|
|
@@ -1543,6 +1608,18 @@ site that has turned them off advertises nothing. The CMS also sends the same
|
|
|
1543
1608
|
endpoint as a `Link` header on every representation of a document, so a sender
|
|
1544
1609
|
that does not parse HTML still finds it.
|
|
1545
1610
|
|
|
1611
|
+
The pingback endpoint follows it, as an absolute URL because the spec asks for
|
|
1612
|
+
one:
|
|
1613
|
+
|
|
1614
|
+
```html
|
|
1615
|
+
<link rel="pingback" href="https://example.com/_geekity/pingback" />
|
|
1616
|
+
```
|
|
1617
|
+
|
|
1618
|
+
It comes from `pingback` on the context, which is there only when the site
|
|
1619
|
+
takes webmentions and the document can be answered: every post, and a page
|
|
1620
|
+
only while it takes comments. The same endpoint goes out in an `X-Pingback`
|
|
1621
|
+
header under the same rule.
|
|
1622
|
+
|
|
1546
1623
|
On the front page it also writes the site's index for language models:
|
|
1547
1624
|
|
|
1548
1625
|
```html
|
|
@@ -1586,7 +1663,17 @@ ask:
|
|
|
1586
1663
|
{% endif %}
|
|
1587
1664
|
```
|
|
1588
1665
|
|
|
1589
|
-
That is what `layouts/post.njk` does
|
|
1666
|
+
That is what `layouts/post.njk` does, and `layouts/page.njk` with it.
|
|
1667
|
+
|
|
1668
|
+
A page takes part only while it takes comments: when its front matter says
|
|
1669
|
+
`comments: true` and the site has not switched comments off. A page is closed
|
|
1670
|
+
by default, as WordPress closes them, and the CMS leaves `conversation` off the
|
|
1671
|
+
context of a closed page however much has been approved against it, so a page
|
|
1672
|
+
that turns comments off shows nothing. A post is different: it keeps its thread
|
|
1673
|
+
after it closes. Webmentions to a page are received and moderated either way,
|
|
1674
|
+
exactly as webmentions to a post are, and appear once the page opens.
|
|
1675
|
+
|
|
1676
|
+
`partials/conversation.njk` is the whole
|
|
1590
1677
|
section — a `div.reactions-section` of the likes, the boosts and the mentions
|
|
1591
1678
|
as facepiles grouped by kind, and then the thread as
|
|
1592
1679
|
`div#comments.comments-area` — and a site replaces it with a
|
|
@@ -1610,34 +1697,37 @@ correctly; one that does can style them apart. The one thing a theme does have
|
|
|
1610
1697
|
to look at is `kind`: a `mention` is in `conversation.mentions` rather than in
|
|
1611
1698
|
the thread, because it is not an answer.
|
|
1612
1699
|
|
|
1613
|
-
| Key | What it holds
|
|
1614
|
-
| -------------------------------------------------- |
|
|
1615
|
-
| `replies` | The replies to the post, oldest first, each carrying its own `replies`. See below.
|
|
1616
|
-
| `likes` | The likes, oldest first, in the same shape.
|
|
1617
|
-
| `boosts` | The boosts, oldest first, in the same shape. A webmention `repost` is one of them.
|
|
1618
|
-
| `mentions` | The pages and fediverse quotes about this post, oldest first, in the same shape.
|
|
1619
|
-
| `
|
|
1620
|
-
| `counts.
|
|
1621
|
-
| `counts.
|
|
1700
|
+
| Key | What it holds |
|
|
1701
|
+
| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
1702
|
+
| `replies` | The replies to the post, oldest first, each carrying its own `replies`. See below. |
|
|
1703
|
+
| `likes` | The likes, oldest first, in the same shape. |
|
|
1704
|
+
| `boosts` | The boosts, oldest first, in the same shape. A webmention `repost` is one of them. |
|
|
1705
|
+
| `mentions` | The pages and fediverse quotes about this post, oldest first, in the same shape. |
|
|
1706
|
+
| `rsvps` | An event's answers, each group `{ value, label, people }`, going, maybe, interested, not going, only with people in it. |
|
|
1707
|
+
| `counts.replies` | How many replies, counted through the whole thread rather than the top of it. |
|
|
1708
|
+
| `counts.likes`, `counts.boosts`, `counts.mentions` | How many of each. |
|
|
1709
|
+
| `counts.rsvps` | How many people answered an event, in every group. |
|
|
1710
|
+
| `counts.total` | All of them added up. Zero never reaches a template: there would be no `conversation` at all. |
|
|
1622
1711
|
|
|
1623
1712
|
Each entry — a reply, a like or a boost — is:
|
|
1624
1713
|
|
|
1625
|
-
| Key | What it holds
|
|
1626
|
-
| ---------------- |
|
|
1627
|
-
| `id` | What it is called: a reply's own note id, which is what an answer to it names.
|
|
1628
|
-
| `source` | `"activitypub"` for a fediverse reply, `"comment"` for one left on the page, `"webmention"` for another page linking here.
|
|
1629
|
-
| `kind` | `"reply"`, `"like"`, `"boost"`, `"repost"` or `"mention"`. A `repost` comes from a webmention; a `mention` is a webmention or an approved fediverse quote.
|
|
1630
|
-
| `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.
|
|
1631
|
-
| `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.
|
|
1632
|
-
| `author.url` | Their profile page, the website a commenter typed, or a webmention author's `u-url`. May be `null`, so guard the link.
|
|
1633
|
-
| `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).
|
|
1634
|
-
| `author.actorId` | Their id, which is what identifies them however they are named. `null` for a native comment.
|
|
1635
|
-
| `url` | Where it can be read: the remote note's `url` for a fediverse reply or quote, the source page for a webmention, and `{permalink}#comment-{id}` — this page's own anchor — for a native comment.
|
|
1636
|
-
| `content` | What it says, **already sanitised**, so print it with `\| safe`. Empty for a like or a boost.
|
|
1637
|
-
| `published` | A `Date`: when it was published, or when it arrived if it did not say. Use the `date` filter.
|
|
1638
|
-
| `inReplyTo` | What it answers — the post's ActivityPub id, or another reply's — and `null` for a reaction.
|
|
1639
|
-
| `status` | `"published"`. On the record for the sources that moderate.
|
|
1640
|
-
| `replies` | The replies to this one, oldest first, nested as deep as the site has seen.
|
|
1714
|
+
| Key | What it holds |
|
|
1715
|
+
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1716
|
+
| `id` | What it is called: a reply's own note id, which is what an answer to it names. |
|
|
1717
|
+
| `source` | `"activitypub"` for a fediverse reply, `"comment"` for one left on the page, `"webmention"` for another page linking here. |
|
|
1718
|
+
| `kind` | `"reply"`, `"like"`, `"boost"`, `"repost"` or `"mention"`. A `repost` comes from a webmention; a `mention` is a webmention or an approved fediverse quote. |
|
|
1719
|
+
| `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. |
|
|
1720
|
+
| `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. |
|
|
1721
|
+
| `author.url` | Their profile page, the website a commenter typed, or a webmention author's `u-url`. May be `null`, so guard the link. |
|
|
1722
|
+
| `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). |
|
|
1723
|
+
| `author.actorId` | Their id, which is what identifies them however they are named. `null` for a native comment. |
|
|
1724
|
+
| `url` | Where it can be read: the remote note's `url` for a fediverse reply or quote, the source page for a webmention, and `{permalink}#comment-{id}` — this page's own anchor — for a native comment. |
|
|
1725
|
+
| `content` | What it says, **already sanitised**, so print it with `\| safe`. Empty for a like or a boost. |
|
|
1726
|
+
| `published` | A `Date`: when it was published, or when it arrived if it did not say. Use the `date` filter. |
|
|
1727
|
+
| `inReplyTo` | What it answers — the post's ActivityPub id, or another reply's — and `null` for a reaction. |
|
|
1728
|
+
| `status` | `"published"`. On the record for the sources that moderate. |
|
|
1729
|
+
| `replies` | The replies to this one, oldest first, nested as deep as the site has seen. |
|
|
1730
|
+
| `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. |
|
|
1641
1731
|
|
|
1642
1732
|
Three rules decide what is in the thread, and they are the CMS's rather than a
|
|
1643
1733
|
theme's: a reply whose author deleted it is gone, and its own answers move up to
|
|
@@ -1898,13 +1988,13 @@ the import above carries `with context`: a macro imported without it cannot see
|
|
|
1898
1988
|
|
|
1899
1989
|
## Filters
|
|
1900
1990
|
|
|
1901
|
-
| Filter | What it does
|
|
1902
|
-
| ---------------------------- |
|
|
1903
|
-
| `date(format, zone, locale)` | Formats a `Date` or a date string. `long` gives `2 September 2026` on an `en` site and `2 septembre 2026` on an `fr` one; `full`, `medium` and `short` are Intl's other date styles, and `readable` (the default) is `long`. `month` gives `September 2026`, `year` gives `2026`, `html` gives `2026-09-02` for a `<time datetime>`, and `iso` gives the full ISO 8601 instant. Every format but `html` and `iso` is written in the site's locale: the `locale` setting, or the `language` when that is empty. Bare `en` writes the day first, as `en-GB` does; `en-US` gives `September 2, 2026`. A date in a file is a UTC instant; every format but `iso` is rendered in the site's `timezone` setting, and `iso` stays the instant. Pass `zone` — an IANA name — to override the setting for one call. Pass `locale` — a BCP 47 tag — to write the words in another language for one call; it comes after `zone`, so pass `none` for the zone to keep the site's: `{{ date \| date("readable", none, lang) }}`. An empty locale, or one that is no tag, writes in the site's. A value that is not a date renders as the empty string. |
|
|
1904
|
-
| `plural(forms, locale)` | Picks the form for a count by its plural category in the site's locale, through `Intl.PluralRules`: `{{ n \| plural({ one: "# reply", other: "# replies" }) }}`. The keys are the CLDR categories (`zero`, `one`, `two`, `few`, `many`, `other`), a category the forms leave out falls back to `other`, and `#` is the count in the locale's digits. Pass `locale` when the strings are in a language of their own: the default theme's words are English, so it passes `"en"`.
|
|
1905
|
-
| `url` | Prefixes a root-relative path with the base URL's path, so a site served from a subdirectory links correctly. Eleventy's filter of the same name.
|
|
1906
|
-
| `absoluteUrl` | The same path as a fully qualified URL against the site's `baseUrl`.
|
|
1907
|
-
| `asset` | The URL of a file in the theme's `static/` directory, with the base path in front and a hash of the file's bytes on the end: `{{ "style.css" \| asset }}` gives `/theme/style.css?v=3f2a9c01b7d4`. The file is found the way `/theme/` finds it, the chosen theme first. A hashed URL is served with `Cache-Control: public, max-age=31536000, immutable`, and editing the file changes the hash on the next render. A file no theme has gets its plain `/theme/` URL.
|
|
1991
|
+
| Filter | What it does |
|
|
1992
|
+
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1993
|
+
| `date(format, zone, locale)` | Formats a `Date` or a date string. `long` gives `2 September 2026` on an `en` site and `2 septembre 2026` on an `fr` one; `full`, `medium` and `short` are Intl's other date styles, and `readable` (the default) is `long`. `datetime` gives `10 October 2026 at 09:00 GMT-5`, the day and the time with the zone named. `month` gives `September 2026`, `year` gives `2026`, `html` gives `2026-09-02` for a `<time datetime>`, and `iso` gives the full ISO 8601 instant. Every format but `html` and `iso` is written in the site's locale: the `locale` setting, or the `language` when that is empty. Bare `en` writes the day first, as `en-GB` does; `en-US` gives `September 2, 2026`. A date in a file is a UTC instant; every format but `iso` is rendered in the site's `timezone` setting, and `iso` stays the instant. Pass `zone` — an IANA name — to override the setting for one call. Pass `locale` — a BCP 47 tag — to write the words in another language for one call; it comes after `zone`, so pass `none` for the zone to keep the site's: `{{ date \| date("readable", none, lang) }}`. An empty locale, or one that is no tag, writes in the site's. A value that is not a date renders as the empty string. |
|
|
1994
|
+
| `plural(forms, locale)` | Picks the form for a count by its plural category in the site's locale, through `Intl.PluralRules`: `{{ n \| plural({ one: "# reply", other: "# replies" }) }}`. The keys are the CLDR categories (`zero`, `one`, `two`, `few`, `many`, `other`), a category the forms leave out falls back to `other`, and `#` is the count in the locale's digits. Pass `locale` when the strings are in a language of their own: the default theme's words are English, so it passes `"en"`. |
|
|
1995
|
+
| `url` | Prefixes a root-relative path with the base URL's path, so a site served from a subdirectory links correctly. Eleventy's filter of the same name. |
|
|
1996
|
+
| `absoluteUrl` | The same path as a fully qualified URL against the site's `baseUrl`. |
|
|
1997
|
+
| `asset` | The URL of a file in the theme's `static/` directory, with the base path in front and a hash of the file's bytes on the end: `{{ "style.css" \| asset }}` gives `/theme/style.css?v=3f2a9c01b7d4`. The file is found the way `/theme/` finds it, the chosen theme first. A hashed URL is served with `Cache-Control: public, max-age=31536000, immutable`, and editing the file changes the hash on the next render. A file no theme has gets its plain `/theme/` URL. |
|
|
1908
1998
|
|
|
1909
1999
|
`date` reads one word rather than parsing it: `{{ "now" | date("year") }}` is
|
|
1910
2000
|
the year at the moment the page is rendered, in the site's own timezone. It is
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{% extends "layouts/base.njk" %}
|
|
2
|
+
{% import "partials/kicker.njk" as kicker with context %}
|
|
3
|
+
|
|
4
|
+
{% block content %}
|
|
5
|
+
<article class="not-found">
|
|
6
|
+
{{ kicker.line("Deleted") }}
|
|
7
|
+
<h1 class="page-title">This content has been deleted.</h1>
|
|
8
|
+
<p>Go <a href="{{ "/" | url }}">home</a>, or <a href="{{ "/search/" | url }}">search the site</a>.</p>
|
|
9
|
+
</article>
|
|
10
|
+
{% endblock %}
|
|
@@ -153,6 +153,9 @@
|
|
|
153
153
|
{% if webmention %}
|
|
154
154
|
<link rel="webmention" href="{{ webmention | url }}">
|
|
155
155
|
{% endif %}
|
|
156
|
+
{% if pingback %}
|
|
157
|
+
<link rel="pingback" href="{{ pingback | absoluteUrl }}">
|
|
158
|
+
{% endif %}
|
|
156
159
|
{#- The site's search, for a browser to offer from its address bar
|
|
157
160
|
(TASK-204). #}
|
|
158
161
|
<link rel="search" type="application/opensearchdescription+xml" title="{{ site.title }}" href="{{ "/opensearch.xml" | url }}">
|
|
@@ -61,6 +61,13 @@
|
|
|
61
61
|
{% endif %}
|
|
62
62
|
</article>
|
|
63
63
|
|
|
64
|
+
{% if conversation %}
|
|
65
|
+
{% include "partials/conversation.njk" %}
|
|
66
|
+
{% endif %}
|
|
67
|
+
{% if commentForm %}
|
|
68
|
+
{% include "partials/comment-form.njk" %}
|
|
69
|
+
{% endif %}
|
|
70
|
+
|
|
64
71
|
{# Only a page whose front matter says `contact: true` has one (TASK-56). #}
|
|
65
72
|
{% if contactForm %}
|
|
66
73
|
{% include "partials/contact-form.njk" %}
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
{% block content %}
|
|
33
33
|
{% set entryUrl = page.url or url %}
|
|
34
|
-
<article class="blog-post h-entry"{{ language.attr(lang) }}>
|
|
34
|
+
<article class="blog-post {{ "h-event" if postType == "event" else "h-entry" }}"{{ language.attr(lang) }}>
|
|
35
35
|
{#- A post with no name of its own (a note, or a reply without a title) is
|
|
36
36
|
its words, so it opens on them in sight. Its page still needs one h1 to
|
|
37
37
|
navigate by, so it gets one that says what it is, who wrote it and when,
|
|
@@ -39,21 +39,23 @@
|
|
|
39
39
|
title and read the note as an article. -#}
|
|
40
40
|
{% if named %}
|
|
41
41
|
<header class="post-header">
|
|
42
|
-
{{ kicker.line(postType | capitalize, false, false, categories) }}
|
|
42
|
+
{{ kicker.line("RSVP" if postType == "rsvp" else postType | capitalize, false, false, categories) }}
|
|
43
43
|
<h1 class="p-name">{{ title }}</h1>
|
|
44
44
|
{% if description %}
|
|
45
45
|
<p class="post-deck p-summary">{{ description }}</p>
|
|
46
46
|
{% endif %}
|
|
47
47
|
</header>
|
|
48
|
+
{% include "partials/event.njk" %}
|
|
48
49
|
{% include "partials/reply-context.njk" %}
|
|
49
50
|
{% include "partials/citations.njk" %}
|
|
50
51
|
{% else %}
|
|
51
52
|
<h1 class="screen-reader-text">
|
|
52
|
-
{{- postType | capitalize if postType in ["reply", "like", "repost", "bookmark", "read"] else "Note" }}
|
|
53
|
+
{{- "RSVP" if postType == "rsvp" else (postType | capitalize if postType in ["event", "reply", "like", "repost", "bookmark", "read"] else "Note") }}
|
|
53
54
|
{%- if bioAuthor.name %} by {{ bioAuthor.name }}{% endif %}
|
|
54
55
|
{%- if date %}, {{ date | date("readable", none, lang) }}{% endif -%}
|
|
55
56
|
</h1>
|
|
56
|
-
{{ kicker.line(postType | capitalize, false, false, categories) }}
|
|
57
|
+
{{ kicker.line("RSVP" if postType == "rsvp" else postType | capitalize, false, false, categories) }}
|
|
58
|
+
{% include "partials/event.njk" %}
|
|
57
59
|
{% include "partials/reply-context.njk" %}
|
|
58
60
|
{% include "partials/citations.njk" %}
|
|
59
61
|
{% endif %}
|
|
@@ -69,6 +71,7 @@
|
|
|
69
71
|
<section class="e-content">
|
|
70
72
|
{#- Inside the content, so a parser that reads only the content of a
|
|
71
73
|
read, as a webmention receiver does, has its sentence. -#}
|
|
74
|
+
{% include "partials/rsvp.njk" %}
|
|
72
75
|
{% include "partials/read.njk" %}
|
|
73
76
|
{{ content | safe }}
|
|
74
77
|
<p class="entry-meta">
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
<div class="search-results">
|
|
38
38
|
{% for post in posts %}
|
|
39
39
|
<article class="search-result h-entry"{{ language.attr(post.lang) }}>
|
|
40
|
-
{{ kicker.line(
|
|
40
|
+
{{ kicker.line("Page" if post.type == "page" else ("RSVP" if post.postType == "rsvp" else post.postType | capitalize), post.date, lang=post.lang) }}
|
|
41
41
|
{#- A post with no name of its own has none to claim, so its first words
|
|
42
42
|
link it without being marked up as one. -#}
|
|
43
43
|
<h2 class="feed-title{% if post.named %} p-name{% endif %}">
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
`og:site_name`), printed after a middle dot as plain text: a site is not an
|
|
24
24
|
author, so it is no `h-card`.
|
|
25
25
|
|
|
26
|
+
The author's `h-card` shows their photo before their name when the page
|
|
27
|
+
gave one (`author.photo.imgHtml`, an `img.u-photo` copied into the site's
|
|
28
|
+
uploads, TASK-199), and a fediverse author's handle after it as its
|
|
29
|
+
`p-nickname`, written `@user@host`.
|
|
30
|
+
|
|
26
31
|
`thumb(url, picture)` is a cited page's thumbnail (TASK-252): a link to the
|
|
27
32
|
page around `picture.imgHtml`, out of the tab order and hidden from assistive
|
|
28
33
|
technology because the title beside it is the same link. A video's carries
|
|
@@ -52,7 +57,9 @@
|
|
|
52
57
|
|
|
53
58
|
{% macro card(author, name) -%}
|
|
54
59
|
<span class="p-author h-card">
|
|
60
|
+
{%- if author.photo %}{{ author.photo.imgHtml | safe }}{% endif -%}
|
|
55
61
|
{%- if author.url %}<a class="u-url p-name" href="{{ author.url }}">{{ name }}</a>
|
|
56
62
|
{%- else %}<span class="p-name">{{ name }}</span>{% endif -%}
|
|
63
|
+
{%- if author.handle %} <span class="p-nickname cite-handle">@{{ author.handle }}</span>{% endif -%}
|
|
57
64
|
</span>
|
|
58
65
|
{%- endmacro %}
|
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
grouped by kind, and the replies as a thread, in the source design's markup
|
|
4
4
|
(decision-16, TASK-84).
|
|
5
5
|
|
|
6
|
-
Rendered from `layouts/post.njk`
|
|
7
|
-
which is only there when there is something
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
Rendered from `layouts/post.njk` and `layouts/page.njk` with the
|
|
7
|
+
`conversation` on the context, which is only there when there is something
|
|
8
|
+
in it and, on a page, only while the page takes comments (TASK-196), so a
|
|
9
|
+
post nobody has answered renders none of this. A site replaces the whole
|
|
10
|
+
section with a `partials/conversation.njk` of its own in the theme it wears;
|
|
11
|
+
the shape it is handed is documented in the theme README under "The
|
|
12
|
+
conversation".
|
|
11
13
|
|
|
12
14
|
The macros come first because Nunjucks defines one where it stands rather
|
|
13
15
|
than hoisting it, and the two sections below call them.
|
|
@@ -80,6 +82,9 @@
|
|
|
80
82
|
</div>
|
|
81
83
|
</footer>
|
|
82
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 %}
|
|
83
88
|
{{ reply.content | safe }}
|
|
84
89
|
</div>
|
|
85
90
|
{#
|
|
@@ -102,6 +107,21 @@
|
|
|
102
107
|
</li>
|
|
103
108
|
{% endmacro %}
|
|
104
109
|
|
|
110
|
+
{#
|
|
111
|
+
Who is coming to an event (TASK-200): each answer it was given, by a
|
|
112
|
+
webmention RSVP or a fediverse Accept, TentativeAccept or Reject, as a
|
|
113
|
+
facepile per answer in the order `conversation.rsvps` gives them, going
|
|
114
|
+
first. A post that is no event has no groups.
|
|
115
|
+
#}
|
|
116
|
+
{% set rsvpIcons = { yes: "✅", maybe: "🤔", interested: "⭐", no: "❌" } %}
|
|
117
|
+
{% if conversation.rsvps.length %}
|
|
118
|
+
<div class="reactions-section rsvps-section">
|
|
119
|
+
{%- for answer in conversation.rsvps %}
|
|
120
|
+
{{- group(answer.people, answer.label, "rsvp-" + answer.value, rsvpIcons[answer.value]) }}
|
|
121
|
+
{%- endfor %}
|
|
122
|
+
</div>
|
|
123
|
+
{% endif %}
|
|
124
|
+
|
|
105
125
|
{#
|
|
106
126
|
The reactions, above the thread. A like and a boost come from the fediverse
|
|
107
127
|
and a `repost` from a webmention; the CMS has already put a repost among the
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{#
|
|
2
|
+
When and where an event is (TASK-200): its `dt-start`, its `dt-end` when it
|
|
3
|
+
has one, and its `p-location`, the place's words or a link to join it
|
|
4
|
+
online. `layouts/post.njk` includes it inside the h-event with `event` on
|
|
5
|
+
the context. The times are the site's clock (decision-11), named with its
|
|
6
|
+
zone so a reader elsewhere can work out their own; the `datetime` is the
|
|
7
|
+
instant.
|
|
8
|
+
#}
|
|
9
|
+
{% if event %}
|
|
10
|
+
<dl class="event-details">
|
|
11
|
+
<dt>When</dt>
|
|
12
|
+
<dd>
|
|
13
|
+
<time class="dt-start" datetime="{{ event.start | date("iso") }}">{{ event.start | date("datetime", none, lang) }}</time>
|
|
14
|
+
{%- if event.end %} to <time class="dt-end" datetime="{{ event.end | date("iso") }}">{{ event.end | date("datetime", none, lang) }}</time>{% endif %}
|
|
15
|
+
</dd>
|
|
16
|
+
{% if event.location %}
|
|
17
|
+
<dt>Where</dt>
|
|
18
|
+
<dd>
|
|
19
|
+
{%- if event.location.kind == "virtual" -%}
|
|
20
|
+
Online at <a class="p-location" href="{{ event.location.url }}">{{ event.location.url | host }}</a>
|
|
21
|
+
{%- else -%}
|
|
22
|
+
<span class="p-location">{{ event.location.name }}</span>
|
|
23
|
+
{%- endif -%}
|
|
24
|
+
</dd>
|
|
25
|
+
{% endif %}
|
|
26
|
+
</dl>
|
|
27
|
+
{% endif %}
|
|
@@ -127,6 +127,34 @@
|
|
|
127
127
|
{{- member("mainEntity", person) }}
|
|
128
128
|
}{% endset %}
|
|
129
129
|
{% set _ = nodes.push(profilePage) %}
|
|
130
|
+
{% elif isEntry and event %}
|
|
131
|
+
{% if event.location.kind == "virtual" %}
|
|
132
|
+
{% set eventLocation = { "@type": "VirtualLocation", "url": event.location.url } %}
|
|
133
|
+
{% set attendance = "https://schema.org/OnlineEventAttendanceMode" %}
|
|
134
|
+
{% elif event.location %}
|
|
135
|
+
{% set eventLocation = { "@type": "Place", "name": event.location.name, "address": event.location.name } %}
|
|
136
|
+
{% set attendance = "https://schema.org/OfflineEventAttendanceMode" %}
|
|
137
|
+
{% else %}
|
|
138
|
+
{% set eventLocation = "" %}
|
|
139
|
+
{% set attendance = "" %}
|
|
140
|
+
{% endif %}
|
|
141
|
+
{% set entry %}
|
|
142
|
+
{
|
|
143
|
+
"@type": "Event"
|
|
144
|
+
{{- member("@id", metaUrl + "#event") }}
|
|
145
|
+
{{- member("name", headline) }}
|
|
146
|
+
{{- member("url", metaUrl) }}
|
|
147
|
+
{{- member("mainEntityOfPage", metaUrl) }}
|
|
148
|
+
{{- member("startDate", event.start | date("iso")) }}
|
|
149
|
+
{{- member("endDate", event.end | date("iso") if event.end else "") }}
|
|
150
|
+
{{- member("location", eventLocation) }}
|
|
151
|
+
{{- member("eventAttendanceMode", attendance) }}
|
|
152
|
+
{{- member("eventStatus", "https://schema.org/EventScheduled") }}
|
|
153
|
+
{{- member("description", metaDescription) }}
|
|
154
|
+
{{- member("image", entryImage) }}
|
|
155
|
+
{{- member("organizer", person or publisher) }}
|
|
156
|
+
}{% endset %}
|
|
157
|
+
{% set _ = nodes.push(entry) %}
|
|
130
158
|
{% elif isEntry %}
|
|
131
159
|
{% set entry %}
|
|
132
160
|
{
|
|
@@ -29,13 +29,14 @@
|
|
|
29
29
|
{% endif %}
|
|
30
30
|
<article class="feed-item h-entry"{{ language.attr(post.lang) }}>
|
|
31
31
|
{% if post.named %}
|
|
32
|
-
{{ kicker.line(post.postType | capitalize, post.date, false, post.categories, lang=post.lang) }}
|
|
32
|
+
{{ kicker.line("RSVP" if post.postType == "rsvp" else post.postType | capitalize, post.date, false, post.categories, lang=post.lang) }}
|
|
33
33
|
{% else %}
|
|
34
|
-
{{ kicker.line(post.postType | capitalize, post.date, post.url, [], post.label, lang=post.lang) }}
|
|
34
|
+
{{ kicker.line("RSVP" if post.postType == "rsvp" else post.postType | capitalize, post.date, post.url, [], post.label, lang=post.lang) }}
|
|
35
35
|
{% endif %}
|
|
36
36
|
{% set cited %}
|
|
37
37
|
{% if post.inReplyTo %}
|
|
38
38
|
{% set inReplyTo = post.inReplyTo %}
|
|
39
|
+
{% set rsvp = post.rsvp %}
|
|
39
40
|
{% set replyContext = post.replyContext %}
|
|
40
41
|
{% set lang = post.lang %}
|
|
41
42
|
{% include "partials/reply-context.njk" %}
|
|
@@ -44,6 +45,8 @@
|
|
|
44
45
|
{% include "partials/citations.njk" %}
|
|
45
46
|
{% endset %}
|
|
46
47
|
{% if not post.named %}{{ cited | safe }}{% endif %}
|
|
48
|
+
{% set rsvp = post.rsvp %}
|
|
49
|
+
{% include "partials/rsvp.njk" %}
|
|
47
50
|
{% set read = post.read %}
|
|
48
51
|
{% include "partials/read.njk" %}
|
|
49
52
|
{% if post.photos.length %}
|
|
@@ -18,19 +18,39 @@
|
|
|
18
18
|
|
|
19
19
|
`replyContext.picture`, when the target has one and the reply shows it, is
|
|
20
20
|
drawn as a thumbnail beside the line, as `citations.njk` draws it (TASK-252).
|
|
21
|
+
|
|
22
|
+
An RSVP (`rsvp` on the context, TASK-198) says "RSVP to" rather than "In
|
|
23
|
+
reply to", and an event's `replyContext.start` and `replyContext.location`
|
|
24
|
+
follow its name as a `dt-start` and a `p-location`. `startDate` is the
|
|
25
|
+
instant to print and `startZone` the zone to print it in: "UTC" for a start
|
|
26
|
+
the event page wrote with no zone, which is the wall clock where the event
|
|
27
|
+
is, and nothing otherwise, so the site's zone applies. The `dt-start`
|
|
28
|
+
carries `start` as the page wrote it.
|
|
29
|
+
|
|
30
|
+
`replyContext.original`, when the target is a silo copy of a post that lists
|
|
31
|
+
the copy as its own (TASK-197), is the post cited: the `h-cite` links the
|
|
32
|
+
original and describes it, so its site finds the link when it is sent a
|
|
33
|
+
webmention. The copy follows the citation as a `u-in-reply-to` of its own,
|
|
34
|
+
outside the `h-cite`, so the silo can thread the reply too.
|
|
21
35
|
#}
|
|
22
36
|
{% import "partials/cited-page.njk" as cited %}
|
|
23
37
|
{% if inReplyTo %}
|
|
24
38
|
{% set picture = replyContext.picture %}
|
|
39
|
+
{% set answered = replyContext.original or inReplyTo %}
|
|
25
40
|
<div class="reply-context cite u-in-reply-to h-cite{% if picture %} cite-with-thumb{% endif %}">
|
|
26
|
-
{%- if picture %}{{ cited.thumb(
|
|
27
|
-
<p class="cite-line small">In reply to
|
|
28
|
-
{{- cited.page(
|
|
29
|
-
{%- if replyContext.
|
|
41
|
+
{%- if picture %}{{ cited.thumb(answered, picture) }}{% endif %}
|
|
42
|
+
<p class="cite-line small">{{ "RSVP to" if rsvp else "In reply to" }}
|
|
43
|
+
{{- cited.page(answered, replyContext) }}
|
|
44
|
+
{%- if replyContext.startDate %}, <time class="dt-start" datetime="{{ replyContext.start }}">{{ replyContext.startDate | date("readable", replyContext.startZone, lang) }}</time>
|
|
45
|
+
{%- elif replyContext.published %}, <time class="dt-published" datetime="{{ replyContext.published | date("iso") }}">{{ replyContext.published | date("readable", none, lang) }}</time>
|
|
30
46
|
{%- endif -%}
|
|
47
|
+
{%- if replyContext.location %}, <span class="p-location">{{ replyContext.location }}</span>{% endif -%}
|
|
31
48
|
</p>
|
|
32
49
|
{% if replyContext.text %}
|
|
33
50
|
<blockquote class="cite-quote p-content">{{ replyContext.text }}</blockquote>
|
|
34
51
|
{% endif %}
|
|
35
52
|
</div>
|
|
53
|
+
{% if replyContext.original %}
|
|
54
|
+
<p class="cite-copy small">Also in reply to <a class="u-in-reply-to" href="{{ inReplyTo }}">its copy on {{ inReplyTo | host }}</a></p>
|
|
55
|
+
{% endif %}
|
|
36
56
|
{% endif %}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{#
|
|
2
|
+
An RSVP's answer, the `p-rsvp` (TASK-198), as the line its content opens
|
|
3
|
+
with. An entry includes it with `rsvp` on the context; a listing sets it
|
|
4
|
+
from the entry it is printing. Nothing is printed for a post that is no
|
|
5
|
+
RSVP.
|
|
6
|
+
#}
|
|
7
|
+
{% if rsvp %}{{ rsvp.line | safe }}{% endif %}
|