@geekity/cms 0.18.0 → 0.19.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 (113) hide show
  1. package/README.md +26 -25
  2. package/admin/components/public-admin-bar.njk +3 -1
  3. package/admin/pages/documents/editor.njk +257 -192
  4. package/admin/static/admin.css +37 -14
  5. package/dist/admin/documents.d.ts +5 -3
  6. package/dist/admin/documents.d.ts.map +1 -1
  7. package/dist/admin/documents.js +76 -20
  8. package/dist/admin/documents.js.map +1 -1
  9. package/dist/admin/editor-layout.d.ts +13 -0
  10. package/dist/admin/editor-layout.d.ts.map +1 -0
  11. package/dist/admin/editor-layout.js +61 -0
  12. package/dist/admin/editor-layout.js.map +1 -0
  13. package/dist/admin/enclosure-field.d.ts +2 -3
  14. package/dist/admin/enclosure-field.d.ts.map +1 -1
  15. package/dist/admin/enclosure-field.js +27 -7
  16. package/dist/admin/enclosure-field.js.map +1 -1
  17. package/dist/admin/location-field.d.ts +4 -3
  18. package/dist/admin/location-field.d.ts.map +1 -1
  19. package/dist/admin/location-field.js +10 -2
  20. package/dist/admin/location-field.js.map +1 -1
  21. package/dist/admin/photo-field.d.ts +2 -3
  22. package/dist/admin/photo-field.d.ts.map +1 -1
  23. package/dist/admin/photo-field.js +4 -2
  24. package/dist/admin/photo-field.js.map +1 -1
  25. package/dist/admin/read-field.d.ts +2 -3
  26. package/dist/admin/read-field.d.ts.map +1 -1
  27. package/dist/admin/read-field.js +12 -4
  28. package/dist/admin/read-field.js.map +1 -1
  29. package/dist/content/kept-properties.d.ts +5 -0
  30. package/dist/content/kept-properties.d.ts.map +1 -0
  31. package/dist/content/kept-properties.js +12 -0
  32. package/dist/content/kept-properties.js.map +1 -0
  33. package/dist/content/location.d.ts +4 -0
  34. package/dist/content/location.d.ts.map +1 -1
  35. package/dist/content/location.js +35 -3
  36. package/dist/content/location.js.map +1 -1
  37. package/dist/content/locations.d.ts +2 -5
  38. package/dist/content/locations.d.ts.map +1 -1
  39. package/dist/content/locations.js +2 -77
  40. package/dist/content/locations.js.map +1 -1
  41. package/dist/content/permalink-file.d.ts +7 -0
  42. package/dist/content/permalink-file.d.ts.map +1 -0
  43. package/dist/content/permalink-file.js +77 -0
  44. package/dist/content/permalink-file.js.map +1 -0
  45. package/dist/federation/article.d.ts +4 -3
  46. package/dist/federation/article.d.ts.map +1 -1
  47. package/dist/federation/article.js +32 -13
  48. package/dist/federation/article.js.map +1 -1
  49. package/dist/federation/citations.d.ts +7 -6
  50. package/dist/federation/citations.d.ts.map +1 -1
  51. package/dist/federation/citations.js +44 -28
  52. package/dist/federation/citations.js.map +1 -1
  53. package/dist/federation/delivery.d.ts.map +1 -1
  54. package/dist/federation/delivery.js +23 -16
  55. package/dist/federation/delivery.js.map +1 -1
  56. package/dist/index.d.ts +5 -4
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/indieauth/bearer.d.ts +10 -6
  60. package/dist/indieauth/bearer.d.ts.map +1 -1
  61. package/dist/indieauth/bearer.js +11 -9
  62. package/dist/indieauth/bearer.js.map +1 -1
  63. package/dist/indieauth/token.js +1 -1
  64. package/dist/indieauth/token.js.map +1 -1
  65. package/dist/micropub/create.d.ts +7 -3
  66. package/dist/micropub/create.d.ts.map +1 -1
  67. package/dist/micropub/create.js +62 -16
  68. package/dist/micropub/create.js.map +1 -1
  69. package/dist/micropub/endpoint.d.ts +4 -5
  70. package/dist/micropub/endpoint.d.ts.map +1 -1
  71. package/dist/micropub/endpoint.js +15 -8
  72. package/dist/micropub/endpoint.js.map +1 -1
  73. package/dist/micropub/media.d.ts +6 -4
  74. package/dist/micropub/media.d.ts.map +1 -1
  75. package/dist/micropub/media.js +7 -5
  76. package/dist/micropub/media.js.map +1 -1
  77. package/dist/micropub/update.d.ts +7 -1
  78. package/dist/micropub/update.d.ts.map +1 -1
  79. package/dist/micropub/update.js +32 -7
  80. package/dist/micropub/update.js.map +1 -1
  81. package/dist/web/admin-bar.d.ts.map +1 -1
  82. package/dist/web/admin-bar.js +25 -0
  83. package/dist/web/admin-bar.js.map +1 -1
  84. package/dist/web/documents.d.ts +21 -6
  85. package/dist/web/documents.d.ts.map +1 -1
  86. package/dist/web/documents.js +23 -12
  87. package/dist/web/documents.js.map +1 -1
  88. package/dist/web/render.d.ts +5 -4
  89. package/dist/web/render.d.ts.map +1 -1
  90. package/dist/web/render.js +20 -11
  91. package/dist/web/render.js.map +1 -1
  92. package/dist/web/routes.d.ts.map +1 -1
  93. package/dist/web/routes.js +15 -4
  94. package/dist/web/routes.js.map +1 -1
  95. package/dist/webmention/fetch-public.d.ts +3 -1
  96. package/dist/webmention/fetch-public.d.ts.map +1 -1
  97. package/dist/webmention/fetch-public.js +17 -11
  98. package/dist/webmention/fetch-public.js.map +1 -1
  99. package/dist/webmention/reply-context.d.ts +18 -5
  100. package/dist/webmention/reply-context.d.ts.map +1 -1
  101. package/dist/webmention/reply-context.js +118 -19
  102. package/dist/webmention/reply-context.js.map +1 -1
  103. package/dist/webmention/reply-contexts.d.ts +17 -14
  104. package/dist/webmention/reply-contexts.d.ts.map +1 -1
  105. package/dist/webmention/reply-contexts.js +32 -21
  106. package/dist/webmention/reply-contexts.js.map +1 -1
  107. package/package.json +9 -9
  108. package/themes/default/README.md +31 -8
  109. package/themes/default/layouts/post.njk +5 -6
  110. package/themes/default/partials/citations.njk +12 -3
  111. package/themes/default/partials/cited-page.njk +41 -0
  112. package/themes/default/partials/post-list.njk +8 -5
  113. package/themes/default/partials/reply-context.njk +2 -9
@@ -3,9 +3,9 @@ import type { DocumentChange } from '../content/sync.ts';
3
3
  import type { HostLookup } from './public-address.ts';
4
4
  import type { ReplyContext } from './reply-context.ts';
5
5
  /**
6
- * Where the fetched reply contexts are kept, relative to the content directory:
7
- * one JSON object keyed by the URL replied to (decision-19). Eleventy reads it
8
- * as the `replyContexts` global.
6
+ * Where the fetched contexts are kept, relative to the content directory: one
7
+ * JSON object keyed by the URL a post replies to, likes, reposts or bookmarks
8
+ * (decision-19). Eleventy reads it as the `replyContexts` global.
9
9
  */
10
10
  export declare const REPLY_CONTEXTS_FILE = "_data/replyContexts.json";
11
11
  /** Where the service reports a target it could not read. */
@@ -14,7 +14,7 @@ export interface ReplyContextLogger {
14
14
  }
15
15
  /** What {@link createReplyContextService} needs. */
16
16
  export interface CreateReplyContextServiceOptions {
17
- /** The index, asked which targets are still replied to. */
17
+ /** The index, asked which targets are still cited. */
18
18
  readonly store: ContentStore;
19
19
  /** Where the file lives. */
20
20
  readonly contentDir: string;
@@ -23,21 +23,24 @@ export interface CreateReplyContextServiceOptions {
23
23
  /** Defaults to `console`. */
24
24
  readonly logger?: ReplyContextLogger | undefined;
25
25
  }
26
- /** Keeps the stored reply contexts in step with the posts that reply. */
26
+ /**
27
+ * Keeps the stored contexts in step with the posts that cite: a reply's
28
+ * `in-reply-to`, and a like's, repost's or bookmark's target (TASK-244).
29
+ */
27
30
  export interface ReplyContextService {
28
31
  /**
29
- * Consider one index change. A reply whose target is new, or has nothing
30
- * stored, has its target fetched; a target no post replies to any more is
31
- * forgotten. Returns at once: the work is queued, so a save never waits on
32
- * a stranger's server.
32
+ * Consider one index change. A target that is new to the post, or has
33
+ * nothing stored, is fetched; a target no post cites any more is forgotten.
34
+ * Returns at once: the work is queued, so a save never waits on a
35
+ * stranger's server.
33
36
  */
34
37
  handle(change: DocumentChange): void;
35
38
  /**
36
- * Fetch every target a live post replies to that the file holds nothing
37
- * for. Run when the site starts serving, because a scan of an index that is
38
- * already up to date reports no change: a site upgraded to reply contexts,
39
- * or one whose file was removed, would otherwise wait for each reply to be
40
- * edited. Queued like {@link ReplyContextService.handle}.
39
+ * Fetch every target a live post cites that the file holds nothing for. Run
40
+ * when the site starts serving, because a scan of an index that is already
41
+ * up to date reports no change: a site upgraded to reply contexts, or one
42
+ * whose file was removed, would otherwise wait for each reply to be edited.
43
+ * Queued like {@link ReplyContextService.handle}.
41
44
  */
42
45
  catchUp(): void;
43
46
  /** The stored context for a target, from the file. Never touches the network. */
@@ -1 +1 @@
1
- {"version":3,"file":"reply-contexts.d.ts","sourceRoot":"","sources":["../../src/webmention/reply-contexts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,6BAA6B,CAAC;AAE9D,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,oDAAoD;AACpD,MAAM,WAAW,gCAAgC;IAC/C,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,4BAA4B;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;CAClD;AAED,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IACrC;;;;;;OAMG;IACH,OAAO,IAAI,IAAI,CAAC;IAChB,iFAAiF;IACjF,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IAC/C,wEAAwE;IACxE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,oDAAoD;AACpD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gCAAgC,GACxC,mBAAmB,CA8FrB"}
1
+ {"version":3,"file":"reply-contexts.d.ts","sourceRoot":"","sources":["../../src/webmention/reply-contexts.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,6BAA6B,CAAC;AAE9D,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,oDAAoD;AACpD,MAAM,WAAW,gCAAgC;IAC/C,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,4BAA4B;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;CAClD;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IACrC;;;;;;OAMG;IACH,OAAO,IAAI,IAAI,CAAC;IAChB,iFAAiF;IACjF,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IAC/C,wEAAwE;IACxE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,oDAAoD;AACpD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gCAAgC,GACxC,mBAAmB,CAiGrB"}
@@ -1,12 +1,13 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import path from 'node:path';
3
+ import { citationsOf } from '../content/citation.js';
3
4
  import { replyTarget } from '../content/post-type.js';
4
5
  import { updateFileAtomically } from '../files/atomic.js';
5
6
  import { fetchReplyContext } from './reply-context.js';
6
7
  /**
7
- * Where the fetched reply contexts are kept, relative to the content directory:
8
- * one JSON object keyed by the URL replied to (decision-19). Eleventy reads it
9
- * as the `replyContexts` global.
8
+ * Where the fetched contexts are kept, relative to the content directory: one
9
+ * JSON object keyed by the URL a post replies to, likes, reposts or bookmarks
10
+ * (decision-19). Eleventy reads it as the `replyContexts` global.
10
11
  */
11
12
  export const REPLY_CONTEXTS_FILE = '_data/replyContexts.json';
12
13
  /** Build the reply context service for one site. */
@@ -47,17 +48,17 @@ export function createReplyContextService(options) {
47
48
  async function refresh(target) {
48
49
  const fetched = await fetchReplyContext(target, { lookup });
49
50
  if (!fetched.ok) {
50
- logger.warn(`Could not read ${target} for a reply's context: ${fetched.reason}`);
51
+ logger.warn(`Could not read ${target} for a citation's context: ${fetched.reason}`);
51
52
  return;
52
53
  }
53
54
  await write(target, fetched.context);
54
55
  }
55
- /** Forget a target, unless a post still replies to it. */
56
+ /** Forget a target, unless a post still cites it. */
56
57
  async function forget(target) {
57
58
  if (!(target in readAll()))
58
59
  return;
59
- const stillAnswered = store.listAll().some((document) => replyTarget(document) === target);
60
- if (!stillAnswered)
60
+ const stillCited = store.listAll().some((document) => targetsOf(document).includes(target));
61
+ if (!stillCited)
61
62
  await write(target, undefined);
62
63
  }
63
64
  let chain = Promise.resolve();
@@ -68,27 +69,30 @@ export function createReplyContextService(options) {
68
69
  }
69
70
  return {
70
71
  handle(change) {
71
- const before = targetOf(change.previous);
72
- const after = targetOf(change.next);
72
+ const before = targetsOf(change.previous);
73
+ const after = targetsOf(change.next);
74
+ const held = readAll();
73
75
  // A scan rebuilds the index from files the contexts file sits beside, so
74
76
  // it only fetches what that file has never held; an edit fetches a
75
77
  // target that changed as well.
76
- if (after !== undefined) {
77
- const stored = after in readAll();
78
- const changed = after !== before && change.origin !== 'scan';
79
- if (!stored || changed)
80
- enqueue(() => refresh(after));
78
+ for (const target of after) {
79
+ const changed = !before.includes(target) && change.origin !== 'scan';
80
+ if (!(target in held) || changed)
81
+ enqueue(() => refresh(target));
82
+ }
83
+ for (const target of before) {
84
+ if (!after.includes(target))
85
+ enqueue(() => forget(target));
81
86
  }
82
- if (before !== undefined && before !== after)
83
- enqueue(() => forget(before));
84
87
  },
85
88
  catchUp() {
86
89
  const held = readAll();
87
90
  const missing = new Set();
88
91
  for (const document of store.listAll()) {
89
- const target = replyTarget(document);
90
- if (target !== undefined && !(target in held))
91
- missing.add(target);
92
+ for (const target of targetsOf(document)) {
93
+ if (!(target in held))
94
+ missing.add(target);
95
+ }
92
96
  }
93
97
  for (const target of missing)
94
98
  enqueue(() => refresh(target));
@@ -101,8 +105,15 @@ export function createReplyContextService(options) {
101
105
  },
102
106
  };
103
107
  }
104
- function targetOf(document) {
105
- return document === undefined ? undefined : replyTarget(document);
108
+ function targetsOf(document) {
109
+ if (document === undefined)
110
+ return [];
111
+ const answered = replyTarget(document);
112
+ const targets = [
113
+ ...(answered === undefined ? [] : [answered]),
114
+ ...citationsOf(document.extra).map((citation) => citation.url),
115
+ ];
116
+ return [...new Set(targets)];
106
117
  }
107
118
  /**
108
119
  * The file's entries, each checked, since a person may have edited it by hand.
@@ -1 +1 @@
1
- {"version":3,"file":"reply-contexts.js","sourceRoot":"","sources":["../../src/webmention/reply-contexts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reply-contexts.js","sourceRoot":"","sources":["../../src/webmention/reply-contexts.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekity/cms",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "type": "module",
5
5
  "description": "A file-first CMS: Markdown content, a SQLite index, a Hono server that is both the editor and the public site.",
6
6
  "license": "MIT",
@@ -28,25 +28,25 @@
28
28
  "LICENSE"
29
29
  ],
30
30
  "dependencies": {
31
- "@fedify/fedify": "^2.3.8",
32
- "@fedify/hono": "^2.3.8",
33
- "@fedify/vocab": "^2.3.8",
34
- "@hono/node-server": "^2.1.1",
31
+ "@fedify/fedify": "^2.4.0",
32
+ "@fedify/hono": "^2.4.0",
33
+ "@fedify/vocab": "^2.4.0",
34
+ "@hono/node-server": "^2.1.3",
35
35
  "@js-temporal/polyfill": "^0.5.1",
36
36
  "chokidar": "^5.0.0",
37
37
  "gray-matter": "^4.0.3",
38
- "hono": "^4.13.9",
38
+ "hono": "^4.13.12",
39
39
  "js-yaml": "^5.4.2",
40
40
  "markdown-it": "^15.0.2",
41
41
  "markdown-it-footnote": "^4.0.0",
42
- "nodemailer": "^10.0.11",
42
+ "nodemailer": "^10.0.13",
43
43
  "nunjucks": "^3.2.4",
44
- "sharp": "^0.35.4"
44
+ "sharp": "^0.35.5"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@11ty/eleventy": "^3.1.6",
48
48
  "@codemirror/lang-markdown": "^6.5.2",
49
- "@fedify/cli": "2.3.8",
49
+ "@fedify/cli": "2.4.0",
50
50
  "@tailwindcss/cli": "^4.3.3",
51
51
  "@types/markdown-it-footnote": "^3.0.4",
52
52
  "@types/node": "^26.6.3",
@@ -26,6 +26,7 @@ themes/default/
26
26
  kicker.njk the line above an entry naming its kind and date
27
27
  reply-context.njk the citation of what a reply answers
28
28
  citations.njk the citation of what a like, repost or bookmark cites
29
+ cited-page.njk the name and author both citations print
29
30
  read.njk what a read post read, and how far
30
31
  bio.njk who an entry is by, as an h-card
31
32
  menu.njk one named menu, as a nav of links
@@ -405,16 +406,37 @@ is an `h3` inside the form's section.
405
406
  `div.reply-context.cite.u-in-reply-to.h-cite`: a rule on the start side, a
406
407
  `p.cite-line` saying "In reply to" and the target's name, author and date as
407
408
  far as they are known, and its excerpt as a `blockquote.cite-quote.p-content`.
408
- An untitled reply prints it under the kicker; a titled reply prints it above
409
- its header. The same partial cites a reply in a feed.
409
+ Where it goes depends on whether the post shows a title. An untitled reply
410
+ opens on it, under the kicker and before its words. A titled reply prints its
411
+ `header.post-header` first and the citation after it, before the `e-content`,
412
+ so the page opens on its title rather than on a link. A listing follows the
413
+ same rule: an untitled entry cites under its kicker, a titled one after its
414
+ title and summary. The same partial cites a reply in a feed. The layouts own
415
+ the placement; the partial owns only what the citation says, and it stays
416
+ inside the `h-entry` wherever it is printed.
410
417
 
411
418
  **A like, a repost or a bookmark cites what it cites** (TASK-169) with
412
419
  `partials/citations.njk`, beside the reply context and drawn the same way: one
413
420
  `div.reply-context.cite.h-cite` per entry of `citations`, classed
414
421
  `u-repost-of`, `u-like-of` or `u-bookmark-of`, whose `p.cite-line` says
415
- Reposted, Liked or Bookmarked and links the target as its `u-url`. Its kicker
416
- and its hidden `h1` say Repost, Like or Bookmark. A listing cites each entry's
417
- from the same partial.
422
+ Reposted, Liked or Bookmarked and links the target as its `u-url`. The link
423
+ says the target's name, as the reply context does, with its author after it as
424
+ a `p-author h-card`, when the target was read when the post was saved
425
+ (TASK-244): its `h-entry` name, its oEmbed title, or its `<title>`. With only
426
+ an author it says "a post", and with neither the bare URL. Its kicker
427
+ and its hidden `h1` say Repost, Like or Bookmark. It is placed as the reply
428
+ context is: at the top of an untitled post, after the header of a titled one.
429
+ A listing cites each entry's from the same partial, by the same rule.
430
+
431
+ **Both citations name the cited page** through `partials/cited-page.njk`, so
432
+ they print its name and author by one rule. A name that already ends in " by "
433
+ and the author's name, in any case, does not print the author again
434
+ (TASK-247): SoundCloud titles a track "Flickermood by Forss" and names Forss
435
+ as its author. The title link stops before " by ", and the words after it
436
+ become the `p-author h-card`, so the line reads "Liked Flickermood by Forss"
437
+ and a parser still reads the whole title as the `p-name`. A name that mentions
438
+ its author anywhere else, such as "Rick Astley - Never Gonna Give You Up" by
439
+ Rick Astley, keeps the author after it.
418
440
 
419
441
  **A read says what was read** (TASK-229) with `partials/read.njk`, a
420
442
  `p.read-line` at the top of the `e-content` that reads like indiebookclub's
@@ -602,7 +624,8 @@ its kicker:
602
624
  **Only an article has a headline.** A note, which has no title, is printed
603
625
  whole as its `e-content`, and the date in its kicker is its `u-url`. A reply is
604
626
  a note that first cites what it answers with `partials/reply-context.njk`, and
605
- a reply with a title is an article that does. An article's categories are in
627
+ a reply with a title is an article that cites it after its title and summary.
628
+ A like, a repost and a bookmark place `partials/citations.njk` the same way. An article's categories are in
606
629
  its kicker; a note's are on its own page.
607
630
 
608
631
  The excerpt is the entry's `summary`, the very line the feeds publish, so a
@@ -1179,7 +1202,7 @@ A document — one post, one page, or one entry of a listing — adds:
1179
1202
  | `lang` | The `lang` front matter as a canonical tag, such as `fr-CA`. Absent when it names none or no tag. |
1180
1203
  | `enclosure` | The post's recording, parsed, with `player` (`audio` or `video`) and `transcript.captions`. Absent with none. |
1181
1204
  | `photos` | The post's photos, each `{ url, alt, html }`; `html` is the `img.u-photo`, responsive. Empty with none. |
1182
- | `citations` | What it reposts, likes or bookmarks, each `{ property, url }` with `property` the mf2 name. Empty with none. |
1205
+ | `citations` | What it reposts, likes or bookmarks, each `{ property, url, context }`; `context` as `replyContext`, when known. |
1183
1206
  | `read` | A read post's `{ status, statusLabel, of, line }`; `of` is `{ name, author, uid, uidLabel, url }`. |
1184
1207
  | `syndicateTo` | On a post's page, the syndication targets it selects, each `{ id, name, url }`. Empty with none. |
1185
1208
  | `syndication` | Its copies elsewhere, each `{ url, label }`: front matter `syndication`, and on its page the copies targets made. |
@@ -1191,7 +1214,7 @@ A document — one post, one page, or one entry of a listing — adds:
1191
1214
  | `postsPage` | The page carrying the listing, as `{ title, url }`, on the front page only. Absent when the site names none. |
1192
1215
  | `archiveMonths` | Every published post as `{ month, posts }`, newest month first. Only on a page that says `archive: true`. |
1193
1216
  | `webmention` | Where a webmention about this page is sent. Only on a rendered document, and only while the site takes them. |
1194
- | `noindex` | `true` on the page of an unlisted document, which the base layout prints as a robots `noindex` meta. Else absent. |
1217
+ | `noindex` | `true` on an unlisted or unpublished page, which the base layout prints as a robots `noindex` meta. Else absent. |
1195
1218
  | `conversation` | The replies, likes and boosts under the post. Only when there are any. See [The conversation](#the-conversation). |
1196
1219
  | everything else | Any front matter key the CMS does not model is on the context under its own name. |
1197
1220
 
@@ -5,8 +5,9 @@
5
5
 
6
6
  An article, and a reply with a title, has the only headline: the title as its
7
7
  `p-name` and the author's `description` under it as the deck, a
8
- `p-summary`. A post with no title opens on its words, set larger. A reply
9
- cites what it answers above its words, or above its header when it has one.
8
+ `p-summary`. A post with no title opens on its words, set larger. What a
9
+ reply answers, and what a like, repost or bookmark cites, opens a post with
10
+ no title and follows the header of one with a title, before its words.
10
11
  Then the Published line, the tags, a rule and the bio. The neighbouring posts,
11
12
  the conversation and the comment form follow the entry.
12
13
 
@@ -36,10 +37,6 @@
36
37
  hidden from sight. It is no `p-name`: a parser would take that as a
37
38
  title and read the note as an article. -#}
38
39
  {% if named %}
39
- {#- A reply cites the post it answers, whose URL is also the link its
40
- webmention points a receiver at. -#}
41
- {% include "partials/reply-context.njk" %}
42
- {% include "partials/citations.njk" %}
43
40
  <header class="post-header">
44
41
  {{ kicker.line(postType | capitalize, false, false, categories) }}
45
42
  <h1 class="p-name">{{ title }}</h1>
@@ -47,6 +44,8 @@
47
44
  <p class="post-deck p-summary">{{ description }}</p>
48
45
  {% endif %}
49
46
  </header>
47
+ {% include "partials/reply-context.njk" %}
48
+ {% include "partials/citations.njk" %}
50
49
  {% else %}
51
50
  <h1 class="screen-reader-text">
52
51
  {{- postType | capitalize if postType in ["reply", "like", "repost", "bookmark", "read"] else "Note" }}
@@ -6,12 +6,21 @@
6
6
  webmention names links to it.
7
7
 
8
8
  Drawn as the same citation block as `reply-context.njk` (doc-9). An entry
9
- includes it with `citations` on the context, a list of `{ property, url }`;
10
- a feed sets it from the entry it is printing.
9
+ includes it with `citations` on the context, a list of `{ property, url,
10
+ context }`; a feed sets it from the entry it is printing.
11
+
12
+ `context` is what the target said about itself when the post was saved or
13
+ synced (TASK-244), only when it said something: its `name` and `author`,
14
+ printed through autoescaping like a reply's context. With a name, the name
15
+ is the link; with only an author, "a post" is; with neither, the bare URL.
11
16
  #}
17
+ {% import "partials/cited-page.njk" as cited %}
12
18
  {% set citationVerbs = { "repost-of": "Reposted", "like-of": "Liked", "bookmark-of": "Bookmarked" } %}
13
19
  {% for citation in citations %}
20
+ {% set citedPage = citation.context %}
14
21
  <div class="reply-context cite u-{{ citation.property }} h-cite">
15
- <p class="cite-line small">{{ citationVerbs[citation.property] }} <a class="u-url" href="{{ citation.url }}">{{ citation.url }}</a></p>
22
+ <p class="cite-line small">{{ citationVerbs[citation.property] }}
23
+ {{- cited.page(citation.url, citedPage) -}}
24
+ </p>
16
25
  </div>
17
26
  {% endfor %}
@@ -0,0 +1,41 @@
1
+ {#
2
+ What a citation says of the page it cites: its name and its author, the part
3
+ of the line after "In reply to", "Liked" and the rest. Shared by
4
+ `reply-context.njk` and `citations.njk` (TASK-247).
5
+
6
+ {% import "partials/cited-page.njk" as cited %}
7
+ {{ cited.page(inReplyTo, replyContext) }}
8
+
9
+ `url` is the cited page, always its `u-url`. `context` is what the page said
10
+ about itself, from the reply contexts file. With a name, the name is the
11
+ link; with only an author, "a post" is; with neither, the bare URL. The
12
+ author follows as an `h-card`.
13
+
14
+ A name that already ends in " by " and the author's name, matched without
15
+ regard to case (SoundCloud's oEmbed gives "Flickermood by Forss" by Forss),
16
+ is not followed by the author again. Its last words become the `h-card`,
17
+ printed as the title wrote them, and the whole name stays the `p-name`, so a
18
+ parser reads the same name and author either way.
19
+ #}
20
+ {% macro page(url, context) %}
21
+ {%- set title = (context.name or "") | trim -%}
22
+ {%- set author = (context.author.name or "") | trim if context.author else "" -%}
23
+ {%- set cut = title.length - author.length - 4 -%}
24
+ {%- set byline = title.slice(cut) if (author and cut > 0) else "" -%}
25
+ {%- set named = byline and byline.slice(0, 4).toLowerCase() == " by " and byline.slice(4).toLowerCase() == author.toLowerCase() -%}
26
+ {%- 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>
27
+ {%- else %}
28
+ {%- if context.name %} <a class="u-url p-name" href="{{ url }}">{{ context.name }}</a>
29
+ {%- elif context.author %} <a class="u-url" href="{{ url }}">a post</a>
30
+ {%- else %} <a class="u-url" href="{{ url }}">{{ url }}</a>
31
+ {%- endif %}
32
+ {%- if context.author %} by {{ card(context.author, context.author.name) }}{% endif %}
33
+ {%- endif %}
34
+ {%- endmacro %}
35
+
36
+ {% macro card(author, name) -%}
37
+ <span class="p-author h-card">
38
+ {%- if author.url %}<a class="u-url p-name" href="{{ author.url }}">{{ name }}</a>
39
+ {%- else %}<span class="p-name">{{ name }}</span>{% endif -%}
40
+ </span>
41
+ {%- endmacro %}
@@ -8,9 +8,10 @@
8
8
  categories it is filed under in its kicker. A note, which has no title, is
9
9
  printed whole as its `e-content`, and its date in the kicker is the link to
10
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.
11
+ title is an article that cites it after its title and summary; a like, a
12
+ repost and a bookmark cite theirs the same way. Tags are deliberately not
13
+ here: an entry's tags belong under the entry, and a feed of twenty posts
14
+ listing everyone's would be a wall of links rather than a list of writing.
14
15
 
15
16
  `feedHeading` is the heading level, which belongs to the layout rather than
16
17
  to the list: a listing is a page of entries and heads each one at 2, and a
@@ -32,16 +33,17 @@
32
33
  {% else %}
33
34
  {{ kicker.line(post.postType | capitalize, post.date, post.url, [], post.label, lang=post.lang) }}
34
35
  {% endif %}
35
- {#- What a reply answers, from the same partial an entry cites it with. -#}
36
+ {% set cited %}
36
37
  {% if post.inReplyTo %}
37
38
  {% set inReplyTo = post.inReplyTo %}
38
39
  {% set replyContext = post.replyContext %}
39
40
  {% set lang = post.lang %}
40
41
  {% include "partials/reply-context.njk" %}
41
42
  {% endif %}
42
- {#- What it reposts, likes or bookmarks, from the partial an entry uses. -#}
43
43
  {% set citations = post.citations %}
44
44
  {% include "partials/citations.njk" %}
45
+ {% endset %}
46
+ {% if not post.named %}{{ cited | safe }}{% endif %}
45
47
  {% set read = post.read %}
46
48
  {% include "partials/read.njk" %}
47
49
  {% if post.photos.length %}
@@ -62,6 +64,7 @@
62
64
  <p>{{ post.summary | truncate(280) }}</p>
63
65
  </div>
64
66
  {% endif %}
67
+ {{ cited | safe }}
65
68
  <p class="feed-more">
66
69
  <a href="{{ post.url | url }}" aria-label="Continue reading: {{ post.title }}">Continue reading<span aria-hidden="true"> &rarr;</span></a>
67
70
  </p>
@@ -16,18 +16,11 @@
16
16
  written in `lang`, the language of the entry it sits in (TASK-189), so a
17
17
  listing sets `lang` from each entry as it sets `replyContext`.
18
18
  #}
19
+ {% import "partials/cited-page.njk" as cited %}
19
20
  {% if inReplyTo %}
20
21
  <div class="reply-context cite u-in-reply-to h-cite">
21
22
  <p class="cite-line small">In reply to
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>
24
- {%- else %} <a class="u-url" href="{{ inReplyTo }}">{{ inReplyTo }}</a>
25
- {%- endif %}
26
- {%- if replyContext.author %} by <span class="p-author h-card">
27
- {%- if replyContext.author.url %}<a class="u-url p-name" href="{{ replyContext.author.url }}">{{ replyContext.author.name }}</a>
28
- {%- else %}<span class="p-name">{{ replyContext.author.name }}</span>{% endif -%}
29
- </span>
30
- {%- endif %}
23
+ {{- cited.page(inReplyTo, replyContext) }}
31
24
  {%- if replyContext.published %}, <time class="dt-published" datetime="{{ replyContext.published | date("iso") }}">{{ replyContext.published | date("readable", none, lang) }}</time>
32
25
  {%- endif -%}
33
26
  </p>