@geekity/cms 0.11.0 → 0.13.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 (240) hide show
  1. package/README.md +177 -6
  2. package/admin/pages/account/login.njk +3 -0
  3. package/admin/pages/documents/editor.njk +7 -0
  4. package/admin/pages/indieauth/consent.njk +51 -0
  5. package/admin/pages/indieauth/refused.njk +11 -0
  6. package/admin/pages/settings/general.njk +9 -0
  7. package/admin/pages/settings/reading.njk +93 -0
  8. package/admin/pages/users/apps.njk +74 -0
  9. package/admin/pages/users/edit.njk +12 -0
  10. package/admin/static/admin.css +27 -0
  11. package/dist/admin/accounts.d.ts +3 -0
  12. package/dist/admin/accounts.d.ts.map +1 -1
  13. package/dist/admin/accounts.js +5 -0
  14. package/dist/admin/accounts.js.map +1 -1
  15. package/dist/admin/documents.d.ts +2 -0
  16. package/dist/admin/documents.d.ts.map +1 -1
  17. package/dist/admin/documents.js +17 -1
  18. package/dist/admin/documents.js.map +1 -1
  19. package/dist/admin/headers.d.ts +5 -1
  20. package/dist/admin/headers.d.ts.map +1 -1
  21. package/dist/admin/headers.js +7 -3
  22. package/dist/admin/headers.js.map +1 -1
  23. package/dist/admin/menu.d.ts.map +1 -1
  24. package/dist/admin/menu.js +2 -1
  25. package/dist/admin/menu.js.map +1 -1
  26. package/dist/admin/routes.d.ts.map +1 -1
  27. package/dist/admin/routes.js +48 -5
  28. package/dist/admin/routes.js.map +1 -1
  29. package/dist/admin/settings-general.js +1 -1
  30. package/dist/admin/settings-general.js.map +1 -1
  31. package/dist/admin/settings-reading.d.ts.map +1 -1
  32. package/dist/admin/settings-reading.js +15 -1
  33. package/dist/admin/settings-reading.js.map +1 -1
  34. package/dist/admin/settings.d.ts +79 -2
  35. package/dist/admin/settings.d.ts.map +1 -1
  36. package/dist/admin/settings.js +168 -2
  37. package/dist/admin/settings.js.map +1 -1
  38. package/dist/admin/templates.d.ts +3 -0
  39. package/dist/admin/templates.d.ts.map +1 -1
  40. package/dist/admin/templates.js +3 -0
  41. package/dist/admin/templates.js.map +1 -1
  42. package/dist/admin/users.d.ts +8 -0
  43. package/dist/admin/users.d.ts.map +1 -1
  44. package/dist/admin/users.js +9 -0
  45. package/dist/admin/users.js.map +1 -1
  46. package/dist/config.d.ts +30 -0
  47. package/dist/config.d.ts.map +1 -1
  48. package/dist/config.js +1 -0
  49. package/dist/config.js.map +1 -1
  50. package/dist/env.d.ts +14 -0
  51. package/dist/env.d.ts.map +1 -1
  52. package/dist/federation/article.d.ts.map +1 -1
  53. package/dist/federation/article.js +18 -5
  54. package/dist/federation/article.js.map +1 -1
  55. package/dist/images/icons.d.ts +44 -25
  56. package/dist/images/icons.d.ts.map +1 -1
  57. package/dist/images/icons.js +205 -60
  58. package/dist/images/icons.js.map +1 -1
  59. package/dist/images/index.d.ts +2 -2
  60. package/dist/images/index.d.ts.map +1 -1
  61. package/dist/images/index.js +1 -1
  62. package/dist/images/index.js.map +1 -1
  63. package/dist/images/markup.d.ts +14 -0
  64. package/dist/images/markup.d.ts.map +1 -1
  65. package/dist/images/markup.js +16 -11
  66. package/dist/images/markup.js.map +1 -1
  67. package/dist/images/variants.d.ts.map +1 -1
  68. package/dist/images/variants.js +3 -4
  69. package/dist/images/variants.js.map +1 -1
  70. package/dist/index.d.ts +14 -4
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +28 -1
  73. package/dist/index.js.map +1 -1
  74. package/dist/indexnow.d.ts +34 -0
  75. package/dist/indexnow.d.ts.map +1 -0
  76. package/dist/indexnow.js +141 -0
  77. package/dist/indexnow.js.map +1 -0
  78. package/dist/indieauth/bearer.d.ts +39 -0
  79. package/dist/indieauth/bearer.d.ts.map +1 -0
  80. package/dist/indieauth/bearer.js +63 -0
  81. package/dist/indieauth/bearer.js.map +1 -0
  82. package/dist/indieauth/client.d.ts +61 -0
  83. package/dist/indieauth/client.d.ts.map +1 -0
  84. package/dist/indieauth/client.js +139 -0
  85. package/dist/indieauth/client.js.map +1 -0
  86. package/dist/indieauth/connected-apps.d.ts +23 -0
  87. package/dist/indieauth/connected-apps.d.ts.map +1 -0
  88. package/dist/indieauth/connected-apps.js +73 -0
  89. package/dist/indieauth/connected-apps.js.map +1 -0
  90. package/dist/indieauth/consent.d.ts +28 -0
  91. package/dist/indieauth/consent.d.ts.map +1 -0
  92. package/dist/indieauth/consent.js +185 -0
  93. package/dist/indieauth/consent.js.map +1 -0
  94. package/dist/indieauth/discovery.d.ts +87 -0
  95. package/dist/indieauth/discovery.d.ts.map +1 -0
  96. package/dist/indieauth/discovery.js +127 -0
  97. package/dist/indieauth/discovery.js.map +1 -0
  98. package/dist/indieauth/grants.d.ts +57 -0
  99. package/dist/indieauth/grants.d.ts.map +1 -0
  100. package/dist/indieauth/grants.js +35 -0
  101. package/dist/indieauth/grants.js.map +1 -0
  102. package/dist/indieauth/identity.d.ts +36 -0
  103. package/dist/indieauth/identity.d.ts.map +1 -0
  104. package/dist/indieauth/identity.js +78 -0
  105. package/dist/indieauth/identity.js.map +1 -0
  106. package/dist/indieauth/redeem.d.ts +47 -0
  107. package/dist/indieauth/redeem.d.ts.map +1 -0
  108. package/dist/indieauth/redeem.js +69 -0
  109. package/dist/indieauth/redeem.js.map +1 -0
  110. package/dist/indieauth/request.d.ts +47 -0
  111. package/dist/indieauth/request.d.ts.map +1 -0
  112. package/dist/indieauth/request.js +104 -0
  113. package/dist/indieauth/request.js.map +1 -0
  114. package/dist/indieauth/token.d.ts +19 -0
  115. package/dist/indieauth/token.d.ts.map +1 -0
  116. package/dist/indieauth/token.js +110 -0
  117. package/dist/indieauth/token.js.map +1 -0
  118. package/dist/indieauth/tokens.d.ts +131 -0
  119. package/dist/indieauth/tokens.d.ts.map +1 -0
  120. package/dist/indieauth/tokens.js +205 -0
  121. package/dist/indieauth/tokens.js.map +1 -0
  122. package/dist/web/archive.d.ts +1 -1
  123. package/dist/web/archive.d.ts.map +1 -1
  124. package/dist/web/archive.js +3 -2
  125. package/dist/web/archive.js.map +1 -1
  126. package/dist/web/context.d.ts +25 -0
  127. package/dist/web/context.d.ts.map +1 -1
  128. package/dist/web/context.js +18 -0
  129. package/dist/web/context.js.map +1 -1
  130. package/dist/web/feed-atom.d.ts.map +1 -1
  131. package/dist/web/feed-atom.js +3 -1
  132. package/dist/web/feed-atom.js.map +1 -1
  133. package/dist/web/feed-item.d.ts +11 -2
  134. package/dist/web/feed-item.d.ts.map +1 -1
  135. package/dist/web/feed-item.js +9 -3
  136. package/dist/web/feed-item.js.map +1 -1
  137. package/dist/web/feed-json.d.ts +4 -0
  138. package/dist/web/feed-json.d.ts.map +1 -1
  139. package/dist/web/feed-json.js +4 -1
  140. package/dist/web/feed-json.js.map +1 -1
  141. package/dist/web/feed-rss.d.ts.map +1 -1
  142. package/dist/web/feed-rss.js +16 -3
  143. package/dist/web/feed-rss.js.map +1 -1
  144. package/dist/web/feed-source.d.ts +28 -0
  145. package/dist/web/feed-source.d.ts.map +1 -1
  146. package/dist/web/feed-source.js +31 -0
  147. package/dist/web/feed-source.js.map +1 -1
  148. package/dist/web/feed-xml.d.ts +2 -0
  149. package/dist/web/feed-xml.d.ts.map +1 -1
  150. package/dist/web/feed-xml.js +2 -0
  151. package/dist/web/feed-xml.js.map +1 -1
  152. package/dist/web/feeds.d.ts.map +1 -1
  153. package/dist/web/feeds.js +8 -1
  154. package/dist/web/feeds.js.map +1 -1
  155. package/dist/web/index.d.ts +3 -1
  156. package/dist/web/index.d.ts.map +1 -1
  157. package/dist/web/index.js +2 -1
  158. package/dist/web/index.js.map +1 -1
  159. package/dist/web/indexnow.d.ts +9 -0
  160. package/dist/web/indexnow.d.ts.map +1 -0
  161. package/dist/web/indexnow.js +27 -0
  162. package/dist/web/indexnow.js.map +1 -0
  163. package/dist/web/llms.d.ts +58 -0
  164. package/dist/web/llms.d.ts.map +1 -0
  165. package/dist/web/llms.js +91 -0
  166. package/dist/web/llms.js.map +1 -0
  167. package/dist/web/locale.d.ts +41 -0
  168. package/dist/web/locale.d.ts.map +1 -0
  169. package/dist/web/locale.js +56 -0
  170. package/dist/web/locale.js.map +1 -0
  171. package/dist/web/manifest.d.ts +50 -0
  172. package/dist/web/manifest.d.ts.map +1 -0
  173. package/dist/web/manifest.js +56 -0
  174. package/dist/web/manifest.js.map +1 -0
  175. package/dist/web/negotiate.d.ts.map +1 -1
  176. package/dist/web/negotiate.js +6 -0
  177. package/dist/web/negotiate.js.map +1 -1
  178. package/dist/web/render.d.ts +6 -1
  179. package/dist/web/render.d.ts.map +1 -1
  180. package/dist/web/render.js +68 -22
  181. package/dist/web/render.js.map +1 -1
  182. package/dist/web/robots.d.ts +89 -0
  183. package/dist/web/robots.d.ts.map +1 -0
  184. package/dist/web/robots.js +259 -0
  185. package/dist/web/robots.js.map +1 -0
  186. package/dist/web/routes.d.ts.map +1 -1
  187. package/dist/web/routes.js +105 -6
  188. package/dist/web/routes.js.map +1 -1
  189. package/dist/web/share-image.d.ts +51 -0
  190. package/dist/web/share-image.d.ts.map +1 -0
  191. package/dist/web/share-image.js +43 -0
  192. package/dist/web/share-image.js.map +1 -0
  193. package/dist/web/sitemap.d.ts +0 -26
  194. package/dist/web/sitemap.d.ts.map +1 -1
  195. package/dist/web/sitemap.js +0 -44
  196. package/dist/web/sitemap.js.map +1 -1
  197. package/dist/web/templates.d.ts +16 -9
  198. package/dist/web/templates.d.ts.map +1 -1
  199. package/dist/web/templates.js +83 -55
  200. package/dist/web/templates.js.map +1 -1
  201. package/dist/web/themes.d.ts +33 -0
  202. package/dist/web/themes.d.ts.map +1 -1
  203. package/dist/web/themes.js +57 -0
  204. package/dist/web/themes.js.map +1 -1
  205. package/dist/webmention/discovery.d.ts +4 -2
  206. package/dist/webmention/discovery.d.ts.map +1 -1
  207. package/dist/webmention/discovery.js +14 -8
  208. package/dist/webmention/discovery.js.map +1 -1
  209. package/dist/webmention/fetch-public.d.ts +2 -0
  210. package/dist/webmention/fetch-public.d.ts.map +1 -1
  211. package/dist/webmention/fetch-public.js +1 -1
  212. package/dist/webmention/fetch-public.js.map +1 -1
  213. package/package.json +7 -2
  214. package/themes/default/README.md +320 -139
  215. package/themes/default/layouts/404.njk +2 -0
  216. package/themes/default/layouts/500.njk +2 -0
  217. package/themes/default/layouts/503.njk +2 -0
  218. package/themes/default/layouts/author.njk +3 -1
  219. package/themes/default/layouts/base.njk +96 -17
  220. package/themes/default/layouts/category.njk +4 -2
  221. package/themes/default/layouts/front-page.njk +7 -2
  222. package/themes/default/layouts/home.njk +10 -0
  223. package/themes/default/layouts/page.njk +7 -4
  224. package/themes/default/layouts/post.njk +35 -25
  225. package/themes/default/layouts/search.njk +5 -9
  226. package/themes/default/layouts/tag.njk +7 -1
  227. package/themes/default/partials/archive.njk +3 -1
  228. package/themes/default/partials/bio.njk +9 -2
  229. package/themes/default/partials/breadcrumbs.njk +20 -0
  230. package/themes/default/partials/comment-form.njk +8 -0
  231. package/themes/default/partials/contact-form.njk +3 -0
  232. package/themes/default/partials/conversation.njk +14 -4
  233. package/themes/default/partials/jsonld.njk +19 -4
  234. package/themes/default/partials/kicker.njk +36 -0
  235. package/themes/default/partials/lang.njk +7 -0
  236. package/themes/default/partials/post-list.njk +43 -47
  237. package/themes/default/partials/reply-context.njk +14 -5
  238. package/themes/default/src/style.css +1109 -0
  239. package/themes/default/static/style.css +2124 -1160
  240. package/themes/default/theme.json +3 -1
@@ -42,7 +42,7 @@
42
42
  {% macro group(items, label, kind, icon, source=false) %}
43
43
  {% if items.length %}
44
44
  <div class="reaction-group {{ kind }}">
45
- <h2 class="reaction-title">{{ label }} ({{ items.length }})</h2>
45
+ <h2 class="reaction-title">{{ label }} <span class="reaction-count">{{ items.length }}</span></h2>
46
46
  <div class="facepile">
47
47
  {%- for item in items %}{{ face(item, icon, (item.url or item.author.url) if source else (item.author.url or item.url)) }}{% endfor %}
48
48
  </div>
@@ -61,6 +61,8 @@
61
61
  <div class="comment-author vcard p-author h-card">
62
62
  {%- if reply.author.avatar %}
63
63
  <img class="avatar u-photo" src="{{ reply.author.avatar }}" alt="" width="40" height="40" loading="lazy">
64
+ {%- else %}
65
+ <span class="comment-avatar-empty" aria-hidden="true">{{ reply.author.name | first | upper }}</span>
64
66
  {%- endif %}
65
67
  <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>
66
68
  </div>
@@ -70,6 +72,11 @@
70
72
  {%- else %}
71
73
  <time class="dt-published" datetime="{{ reply.published | date("iso") }}">{{ reply.published | date }}</time>
72
74
  {%- endif %}
75
+ {%- if reply.source == "webmention" %}
76
+ <span class="comment-source">via webmention</span>
77
+ {%- elif reply.source == "activitypub" %}
78
+ <span class="comment-source">via the fediverse</span>
79
+ {%- endif %}
73
80
  </div>
74
81
  </footer>
75
82
  <div class="comment-content e-content">
@@ -111,8 +118,11 @@
111
118
 
112
119
  {#
113
120
  And the thread. The title counts the whole of it rather than the top level,
114
- which is what `counts.replies` is, and names the post the way the source
115
- theme does.
121
+ which is what `counts.replies` is. It does not quote the post's title: the
122
+ post is the page it sits under, and a note has no title to quote (TASK-186).
123
+ The count goes through `plural` with "en" because the words are English: a
124
+ theme that translates them drops the "en" and gives the forms its language
125
+ has, so the site's locale picks between them.
116
126
 
117
127
  "Comments are closed." is printed under a post that has been answered and is
118
128
  no longer taking comments. That a post is closed is what the absence of
@@ -123,7 +133,7 @@
123
133
  {% if conversation.replies.length %}
124
134
  <div id="comments" class="comments-area">
125
135
  <h2 class="comments-title">
126
- {%- if conversation.counts.replies == 1 %}One comment{% else %}{{ conversation.counts.replies }} comments{% endif %} on &ldquo;<span>{{ title }}</span>&rdquo;
136
+ {{- conversation.counts.replies | plural({ one: "One reply", other: "# replies" }, "en") -}}
127
137
  </h2>
128
138
 
129
139
  <ol class="comment-list">
@@ -42,9 +42,6 @@
42
42
  {% for link in siteAuthor.links %}{% set _ = sameAs.push(link.href) %}{% endfor %}
43
43
  {% if personUrl %}{% set _ = sameAs.push(personUrl) %}{% endif %}
44
44
  {% set address = { "@type": "PostalAddress", "addressLocality": siteAuthor.location } if siteAuthor.location else "" %}
45
- {#- An author archive is the only page that is about a person: a listing whose
46
- `author` is whose page this is. -#}
47
- {% set isProfilePage = pagination and author.url and url and (author.url in url) %}
48
45
  {% set entryType = "BlogPosting" if type == "post" else "Article" %}
49
46
  {% set nodes = [] %}
50
47
  {% set website %}
@@ -67,6 +64,9 @@
67
64
  "query-input": "required name=search_term_string"
68
65
  }) }}
69
66
  {{- member("publisher", person) }}
67
+ {#- What the site is about, on the homepage of a solo author blog
68
+ (TASK-180): the site's author, and nobody on any other site. #}
69
+ {{- member("about", { "@id": (soloAuthor.url | absoluteUrl) + "#person" } if atRoot and soloAuthor.url else "") }}
70
70
  }{% endset %}
71
71
  {% set _ = nodes.push(website) %}
72
72
  {% if personId %}
@@ -84,7 +84,7 @@
84
84
  }{% endset %}
85
85
  {% set _ = nodes.push(profile) %}
86
86
  {% endif %}
87
- {% if isProfilePage %}
87
+ {% if isAuthorArchive %}
88
88
  {% set profilePage %}
89
89
  {
90
90
  "@type": "ProfilePage"
@@ -110,6 +110,21 @@
110
110
  }{% endset %}
111
111
  {% set _ = nodes.push(entry) %}
112
112
  {% endif %}
113
+ {#- Where the page sits, from the trail `layouts/base.njk` builds and the
114
+ visible breadcrumb prints (TASK-150). -#}
115
+ {% if breadcrumbs.length %}
116
+ {% set trail = [] %}
117
+ {% for crumb in breadcrumbs %}
118
+ {% set _ = trail.push({ "@type": "ListItem", "position": loop.index, "name": crumb.name, "item": crumb.url | absoluteUrl }) %}
119
+ {% endfor %}
120
+ {% set breadcrumbList %}
121
+ {
122
+ "@type": "BreadcrumbList"
123
+ {{- member("@id", metaUrl + "#breadcrumb") }}
124
+ {{- member("itemListElement", trail) }}
125
+ }{% endset %}
126
+ {% set _ = nodes.push(breadcrumbList) %}
127
+ {% endif %}
113
128
  <script type="application/ld+json">
114
129
  {
115
130
  "@context": "https://schema.org",
@@ -0,0 +1,36 @@
1
+ {#
2
+ The kicker: what an entry is, said once, small, above it (doc-9). The kind
3
+ word first, then the date, then the categories, each after a middle dot the
4
+ screen reader skips.
5
+
6
+ Import it with the context, because the category links read the archive
7
+ base off `site`:
8
+
9
+ {% import "partials/kicker.njk" as kicker with context %}
10
+ {{ kicker.line("Note", post.date, post.url) }}
11
+
12
+ `kind` is the word printed: Article, Note or Reply for a post (its
13
+ `postType`, capitalised), Page for a page, and whatever names an archive or
14
+ an error page. `date` is the entry's `dt-published`, printed long. With
15
+ `href` the date is the entry's `u-url`, which is how a feed links an entry
16
+ that has no title to link; an entry with no date links `label` instead.
17
+ `categories` are printed as `p-category` links. `lang` is the entry's own
18
+ language when it names one, so its date is written in that language rather
19
+ than the site's (TASK-189); a listing passes `lang=post.lang`.
20
+ #}
21
+ {% macro line(kind, date=false, href=false, categories=[], label="", lang=false) %}
22
+ <p class="kicker">
23
+ <span class="kicker-kind">{{ kind }}</span>
24
+ {%- if href %}
25
+ <span class="kicker-dot" aria-hidden="true">·</span>
26
+ <a href="{{ href | url }}" class="u-url">{% if date %}<time class="feed-date dt-published" datetime="{{ date | date("iso") }}">{{ date | date("readable", none, lang) }}</time>{% else %}{{ label }}{% endif %}</a>
27
+ {%- elif date %}
28
+ <span class="kicker-dot" aria-hidden="true">·</span>
29
+ <time class="feed-date dt-published" datetime="{{ date | date("iso") }}">{{ date | date("readable", none, lang) }}</time>
30
+ {%- endif %}
31
+ {%- for category in categories %}
32
+ <span class="kicker-dot" aria-hidden="true">·</span>
33
+ <a href="{{ ("/" + (site.categoryBase or "category") + "/" + (category | urlencode) + "/") | url }}" class="p-category" rel="category">{{ category }}</a>
34
+ {%- endfor %}
35
+ </p>
36
+ {% endmacro %}
@@ -0,0 +1,7 @@
1
+ {#- The `lang` attribute of an article written in a language other than the
2
+ site's (TASK-154), with its leading space, and nothing for one in the
3
+ site's own: the `<html lang>` already names that. Imported with context,
4
+ since the site's language is what it compares against. -#}
5
+ {% macro attr(tag) -%}
6
+ {%- if tag and tag != (site.language | default("en")) %} lang="{{ tag }}"{% endif -%}
7
+ {%- endmacro %}
@@ -1,21 +1,24 @@
1
1
  {#
2
- The feed a listing is made of: `h-feed` of `h-entry` items, as the source
3
- design lists them (decision-16).
2
+ The feed a listing is made of: `h-feed` of `h-entry` items (doc-9).
4
3
 
5
- Expects `posts`. A note, which has no title, is printed whole as its
6
- `e-content`, with its date as the link to it. Every other entry prints its
7
- title as a linked `p-name`, its `summary` — the very line the feeds publish —
8
- as a `p-summary` cut to about 280 characters, a Continue reading link, its
9
- publish date and the categories it is filed under. Tags are deliberately not here: an entry's tags belong
10
- under the entry, and a feed of twenty posts listing everyone's would be a
11
- wall of links rather than a list of writing.
4
+ Expects `posts`. Every entry opens on a kicker naming its kind and its date.
5
+ An article is the only entry with a headline: its title as a linked
6
+ `p-name`, its `summary` (the very line the feeds publish) as a `p-summary`
7
+ cut to about 280 characters, and a Continue reading link, with the
8
+ categories it is filed under in its kicker. A note, which has no title, is
9
+ printed whole as its `e-content`, and its date in the kicker is the link to
10
+ it. A reply is a note that first cites what it answers, and a reply with a
11
+ title is an article that does. Tags are deliberately not here: an entry's
12
+ tags belong under the entry, and a feed of twenty posts listing everyone's
13
+ would be a wall of links rather than a list of writing.
12
14
 
13
15
  `feedHeading` is the heading level, which belongs to the layout rather than
14
16
  to the list: a listing is a page of entries and heads each one at 2, and a
15
17
  front page whose feed sits under a heading of its own sets 3 so the outline
16
18
  never skips a level.
17
19
  #}
18
- {% import "partials/tags.njk" as taxonomy with context %}
20
+ {% import "partials/kicker.njk" as kicker with context %}
21
+ {% import "partials/lang.njk" as language with context %}
19
22
  {% set feedTitleTag = "h" + (feedHeading | default(2)) %}
20
23
  {% if posts.length %}
21
24
  <div class="feed h-feed">
@@ -23,44 +26,37 @@
23
26
  {% if not loop.first %}
24
27
  <hr class="feed-separator">
25
28
  {% endif %}
26
- <article class="feed-item h-entry">
27
- <div class="feed-content">
28
- {% if post.inReplyTo %}
29
- <p class="feed-reply small">In reply to <a class="u-in-reply-to" href="{{ post.inReplyTo }}">{{ post.inReplyTo }}</a></p>
30
- {% endif %}
31
- {% if not post.named %}
32
- <div class="feed-excerpt e-content">{{ post.content | safe }}</div>
33
- {% else %}
34
- <{{ feedTitleTag }} class="feed-title p-name">
35
- <a href="{{ post.url | url }}" class="u-url">{{ post.title }}</a>
36
- </{{ feedTitleTag }}>
37
- {% if post.summary %}
38
- <div class="feed-excerpt p-summary">
39
- {#- `truncate` cuts at the last space before the length and adds an
40
- ellipsis, so a description short enough is printed whole and a long
41
- one never breaks a word. -#}
42
- <p>{{ post.summary | truncate(280) }}</p>
43
- </div>
44
- {% endif %}
45
- <p class="feed-more">
46
- <a href="{{ post.url | url }}" aria-label="Continue reading: {{ post.title }}">Continue reading<span aria-hidden="true"> &rarr;</span></a>
47
- </p>
48
- {% endif %}
49
- <div class="feed-meta">
50
- {% if not post.named %}
51
- <p>
52
- <a href="{{ post.url | url }}" class="u-url">{% if post.date %}<time class="feed-date dt-published" datetime="{{ post.date | date("iso") }}">{{ post.date | date }}</time>{% else %}{{ post.label }}{% endif %}</a>
53
- </p>
54
- {% elif post.date %}
55
- <p>
56
- <time class="feed-date dt-published" datetime="{{ post.date | date("iso") }}">
57
- {{ post.date | date }}
58
- </time>
59
- </p>
60
- {% endif %}
61
- {{ taxonomy.categories(post.categories) }}
62
- </div>
29
+ <article class="feed-item h-entry"{{ language.attr(post.lang) }}>
30
+ {% if post.named %}
31
+ {{ kicker.line(post.postType | capitalize, post.date, false, post.categories, lang=post.lang) }}
32
+ {% else %}
33
+ {{ kicker.line(post.postType | capitalize, post.date, post.url, [], post.label, lang=post.lang) }}
34
+ {% endif %}
35
+ {#- What a reply answers, from the same partial an entry cites it with. -#}
36
+ {% if post.inReplyTo %}
37
+ {% set inReplyTo = post.inReplyTo %}
38
+ {% set replyContext = post.replyContext %}
39
+ {% set lang = post.lang %}
40
+ {% include "partials/reply-context.njk" %}
41
+ {% endif %}
42
+ {% if not post.named %}
43
+ <div class="feed-excerpt e-content">{{ post.content | safe }}</div>
44
+ {% else %}
45
+ <{{ feedTitleTag }} class="feed-title p-name">
46
+ <a href="{{ post.url | url }}" class="u-url">{{ post.title }}</a>
47
+ </{{ feedTitleTag }}>
48
+ {% if post.summary %}
49
+ <div class="feed-excerpt p-summary">
50
+ {#- `truncate` cuts at the last space before the length and adds an
51
+ ellipsis, so a description short enough is printed whole and a long
52
+ one never breaks a word. -#}
53
+ <p>{{ post.summary | truncate(280) }}</p>
63
54
  </div>
55
+ {% endif %}
56
+ <p class="feed-more">
57
+ <a href="{{ post.url | url }}" aria-label="Continue reading: {{ post.title }}">Continue reading<span aria-hidden="true"> &rarr;</span></a>
58
+ </p>
59
+ {% endif %}
64
60
  </article>
65
61
  {% endfor %}
66
62
  </div>
@@ -3,15 +3,24 @@
3
3
  `u-in-reply-to h-cite` that always carries the target's URL, so a parser
4
4
  reads what this post answers even when nothing more is known about it.
5
5
 
6
+ Drawn as the citation block (doc-9): a rule on the start side, a sans line
7
+ naming the target, and its words as an italic quote. An entry includes it
8
+ with `inReplyTo` and `replyContext` on the context; a feed sets both from
9
+ the entry it is printing.
10
+
6
11
  `replyContext` is what the target said about itself when the reply was saved
7
12
  or synced: its name, a short excerpt, its author and its date, each only when
8
13
  it said so. It is somebody else's words, so every piece is printed through
9
- autoescaping and none of it with `safe`.
14
+ autoescaping and none of it with `safe`. With a name, the name is the link;
15
+ with only an author, "a post" is; with neither, the bare URL. Its date is
16
+ written in `lang`, the language of the entry it sits in (TASK-189), so a
17
+ listing sets `lang` from each entry as it sets `replyContext`.
10
18
  #}
11
19
  {% if inReplyTo %}
12
- <div class="reply-context u-in-reply-to h-cite">
13
- <p class="small">In reply to
20
+ <div class="reply-context cite u-in-reply-to h-cite">
21
+ <p class="cite-line small">In reply to
14
22
  {%- if replyContext.name %} <a class="u-url p-name" href="{{ inReplyTo }}">{{ replyContext.name }}</a>
23
+ {%- elif replyContext.author %} <a class="u-url" href="{{ inReplyTo }}">a post</a>
15
24
  {%- else %} <a class="u-url" href="{{ inReplyTo }}">{{ inReplyTo }}</a>
16
25
  {%- endif %}
17
26
  {%- if replyContext.author %} by <span class="p-author h-card">
@@ -19,11 +28,11 @@
19
28
  {%- else %}<span class="p-name">{{ replyContext.author.name }}</span>{% endif -%}
20
29
  </span>
21
30
  {%- endif %}
22
- {%- if replyContext.published %} on <time class="dt-published" datetime="{{ replyContext.published | date("iso") }}">{{ replyContext.published | date }}</time>
31
+ {%- if replyContext.published %}, <time class="dt-published" datetime="{{ replyContext.published | date("iso") }}">{{ replyContext.published | date("readable", none, lang) }}</time>
23
32
  {%- endif -%}
24
33
  </p>
25
34
  {% if replyContext.text %}
26
- <blockquote class="p-content">{{ replyContext.text }}</blockquote>
35
+ <blockquote class="cite-quote p-content">{{ replyContext.text }}</blockquote>
27
36
  {% endif %}
28
37
  </div>
29
38
  {% endif %}