@geekity/cms 0.5.0 → 0.7.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 (172) hide show
  1. package/README.md +78 -24
  2. package/admin/pages/documents/editor.njk +13 -1
  3. package/admin/pages/navigation/menus.njk +8 -5
  4. package/admin/pages/users/edit.njk +25 -2
  5. package/admin/static/admin.css +18 -3
  6. package/dist/admin/accounts.d.ts +10 -0
  7. package/dist/admin/accounts.d.ts.map +1 -1
  8. package/dist/admin/accounts.js +15 -3
  9. package/dist/admin/accounts.js.map +1 -1
  10. package/dist/admin/comments.d.ts.map +1 -1
  11. package/dist/admin/comments.js +2 -1
  12. package/dist/admin/comments.js.map +1 -1
  13. package/dist/admin/documents.d.ts +3 -0
  14. package/dist/admin/documents.d.ts.map +1 -1
  15. package/dist/admin/documents.js +51 -11
  16. package/dist/admin/documents.js.map +1 -1
  17. package/dist/admin/federation.d.ts.map +1 -1
  18. package/dist/admin/federation.js +3 -2
  19. package/dist/admin/federation.js.map +1 -1
  20. package/dist/admin/preview.js +3 -0
  21. package/dist/admin/preview.js.map +1 -1
  22. package/dist/admin/routes.d.ts.map +1 -1
  23. package/dist/admin/routes.js +2 -1
  24. package/dist/admin/routes.js.map +1 -1
  25. package/dist/admin/users.d.ts +24 -0
  26. package/dist/admin/users.d.ts.map +1 -1
  27. package/dist/admin/users.js +102 -30
  28. package/dist/admin/users.js.map +1 -1
  29. package/dist/comments/submission.d.ts.map +1 -1
  30. package/dist/comments/submission.js +2 -1
  31. package/dist/comments/submission.js.map +1 -1
  32. package/dist/config.d.ts +10 -0
  33. package/dist/config.d.ts.map +1 -1
  34. package/dist/config.js +2 -0
  35. package/dist/config.js.map +1 -1
  36. package/dist/content/document.d.ts +18 -7
  37. package/dist/content/document.d.ts.map +1 -1
  38. package/dist/content/document.js +1 -0
  39. package/dist/content/document.js.map +1 -1
  40. package/dist/content/index.d.ts +2 -0
  41. package/dist/content/index.d.ts.map +1 -1
  42. package/dist/content/index.js +1 -0
  43. package/dist/content/index.js.map +1 -1
  44. package/dist/content/parser.d.ts.map +1 -1
  45. package/dist/content/parser.js +19 -1
  46. package/dist/content/parser.js.map +1 -1
  47. package/dist/content/post-type.d.ts +48 -0
  48. package/dist/content/post-type.d.ts.map +1 -0
  49. package/dist/content/post-type.js +79 -0
  50. package/dist/content/post-type.js.map +1 -0
  51. package/dist/content/store.d.ts.map +1 -1
  52. package/dist/content/store.js +17 -2
  53. package/dist/content/store.js.map +1 -1
  54. package/dist/content/sync.d.ts.map +1 -1
  55. package/dist/content/sync.js +6 -0
  56. package/dist/content/sync.js.map +1 -1
  57. package/dist/content/writer.d.ts +1 -1
  58. package/dist/content/writer.d.ts.map +1 -1
  59. package/dist/content/writer.js +9 -2
  60. package/dist/content/writer.js.map +1 -1
  61. package/dist/federation/article.d.ts +18 -9
  62. package/dist/federation/article.d.ts.map +1 -1
  63. package/dist/federation/article.js +87 -17
  64. package/dist/federation/article.js.map +1 -1
  65. package/dist/federation/index.d.ts +1 -1
  66. package/dist/federation/index.d.ts.map +1 -1
  67. package/dist/federation/index.js +1 -1
  68. package/dist/federation/index.js.map +1 -1
  69. package/dist/federation/mount.d.ts.map +1 -1
  70. package/dist/federation/mount.js +19 -6
  71. package/dist/federation/mount.js.map +1 -1
  72. package/dist/index.d.ts +13 -6
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +23 -4
  75. package/dist/index.js.map +1 -1
  76. package/dist/notifications/comments.d.ts.map +1 -1
  77. package/dist/notifications/comments.js +2 -1
  78. package/dist/notifications/comments.js.map +1 -1
  79. package/dist/notifications/digest.d.ts.map +1 -1
  80. package/dist/notifications/digest.js +2 -1
  81. package/dist/notifications/digest.js.map +1 -1
  82. package/dist/web/archive.d.ts +1 -1
  83. package/dist/web/archive.d.ts.map +1 -1
  84. package/dist/web/archive.js +2 -1
  85. package/dist/web/archive.js.map +1 -1
  86. package/dist/web/authors.d.ts +15 -1
  87. package/dist/web/authors.d.ts.map +1 -1
  88. package/dist/web/authors.js +9 -1
  89. package/dist/web/authors.js.map +1 -1
  90. package/dist/web/context.d.ts +22 -2
  91. package/dist/web/context.d.ts.map +1 -1
  92. package/dist/web/context.js +5 -0
  93. package/dist/web/context.js.map +1 -1
  94. package/dist/web/conversation.d.ts.map +1 -1
  95. package/dist/web/conversation.js +2 -1
  96. package/dist/web/conversation.js.map +1 -1
  97. package/dist/web/feed-atom.d.ts.map +1 -1
  98. package/dist/web/feed-atom.js +14 -2
  99. package/dist/web/feed-atom.js.map +1 -1
  100. package/dist/web/feed-item.d.ts +21 -7
  101. package/dist/web/feed-item.d.ts.map +1 -1
  102. package/dist/web/feed-item.js +13 -6
  103. package/dist/web/feed-item.js.map +1 -1
  104. package/dist/web/feed-json.d.ts +13 -2
  105. package/dist/web/feed-json.d.ts.map +1 -1
  106. package/dist/web/feed-json.js +3 -1
  107. package/dist/web/feed-json.js.map +1 -1
  108. package/dist/web/feed-rss.d.ts.map +1 -1
  109. package/dist/web/feed-rss.js +2 -2
  110. package/dist/web/feed-rss.js.map +1 -1
  111. package/dist/web/feed-xml.d.ts +2 -0
  112. package/dist/web/feed-xml.d.ts.map +1 -1
  113. package/dist/web/feed-xml.js +2 -0
  114. package/dist/web/feed-xml.js.map +1 -1
  115. package/dist/web/feeds.d.ts +1 -1
  116. package/dist/web/feeds.d.ts.map +1 -1
  117. package/dist/web/feeds.js.map +1 -1
  118. package/dist/web/index.d.ts +4 -4
  119. package/dist/web/index.d.ts.map +1 -1
  120. package/dist/web/index.js +1 -1
  121. package/dist/web/index.js.map +1 -1
  122. package/dist/web/navigation.d.ts +106 -28
  123. package/dist/web/navigation.d.ts.map +1 -1
  124. package/dist/web/navigation.js +135 -49
  125. package/dist/web/navigation.js.map +1 -1
  126. package/dist/web/render.d.ts +9 -0
  127. package/dist/web/render.d.ts.map +1 -1
  128. package/dist/web/render.js +19 -1
  129. package/dist/web/render.js.map +1 -1
  130. package/dist/web/routes.d.ts.map +1 -1
  131. package/dist/web/routes.js +2 -1
  132. package/dist/web/routes.js.map +1 -1
  133. package/dist/webmention/index.d.ts +6 -0
  134. package/dist/webmention/index.d.ts.map +1 -1
  135. package/dist/webmention/index.js +3 -0
  136. package/dist/webmention/index.js.map +1 -1
  137. package/dist/webmention/links.d.ts +5 -0
  138. package/dist/webmention/links.d.ts.map +1 -1
  139. package/dist/webmention/links.js +14 -7
  140. package/dist/webmention/links.js.map +1 -1
  141. package/dist/webmention/microformats.d.ts +21 -0
  142. package/dist/webmention/microformats.d.ts.map +1 -1
  143. package/dist/webmention/microformats.js +35 -5
  144. package/dist/webmention/microformats.js.map +1 -1
  145. package/dist/webmention/public-address.d.ts +30 -0
  146. package/dist/webmention/public-address.d.ts.map +1 -0
  147. package/dist/webmention/public-address.js +71 -0
  148. package/dist/webmention/public-address.js.map +1 -0
  149. package/dist/webmention/receive.d.ts.map +1 -1
  150. package/dist/webmention/receive.js +1 -23
  151. package/dist/webmention/receive.js.map +1 -1
  152. package/dist/webmention/reply-context.d.ts +67 -0
  153. package/dist/webmention/reply-context.d.ts.map +1 -0
  154. package/dist/webmention/reply-context.js +189 -0
  155. package/dist/webmention/reply-context.js.map +1 -0
  156. package/dist/webmention/reply-contexts.d.ts +50 -0
  157. package/dist/webmention/reply-contexts.d.ts.map +1 -0
  158. package/dist/webmention/reply-contexts.js +163 -0
  159. package/dist/webmention/reply-contexts.js.map +1 -0
  160. package/dist/webmention/service.d.ts.map +1 -1
  161. package/dist/webmention/service.js +9 -2
  162. package/dist/webmention/service.js.map +1 -1
  163. package/package.json +10 -10
  164. package/themes/default/README.md +25 -10
  165. package/themes/default/layouts/base.njk +5 -3
  166. package/themes/default/layouts/post.njk +8 -0
  167. package/themes/default/layouts/search.njk +4 -2
  168. package/themes/default/partials/bio.njk +5 -1
  169. package/themes/default/partials/menu.njk +6 -4
  170. package/themes/default/partials/post-list.njk +17 -5
  171. package/themes/default/partials/reply-context.njk +29 -0
  172. package/themes/default/static/style.css +28 -10
@@ -0,0 +1,163 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { replyTarget } from '../content/post-type.js';
4
+ import { updateFileAtomically } from '../files/atomic.js';
5
+ import { fetchReplyContext } from './reply-context.js';
6
+ /**
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.
10
+ */
11
+ export const REPLY_CONTEXTS_FILE = '_data/replyContexts.json';
12
+ /** Build the reply context service for one site. */
13
+ export function createReplyContextService(options) {
14
+ const { store, lookup } = options;
15
+ const logger = options.logger ?? console;
16
+ const file = path.join(options.contentDir, ...REPLY_CONTEXTS_FILE.split('/'));
17
+ let cachedText;
18
+ let cached = {};
19
+ /** The whole file, parsed only when its bytes changed since the last read. */
20
+ function readAll() {
21
+ let text;
22
+ try {
23
+ text = readFileSync(file, 'utf8');
24
+ }
25
+ catch {
26
+ cachedText = undefined;
27
+ cached = {};
28
+ return cached;
29
+ }
30
+ if (text !== cachedText) {
31
+ cachedText = text;
32
+ cached = parseContexts(text);
33
+ }
34
+ return cached;
35
+ }
36
+ /** Rewrite the file with one target's entry set, or removed when `undefined`. */
37
+ async function write(target, context) {
38
+ await updateFileAtomically(file, (current) => {
39
+ const all = current === undefined ? {} : parseContexts(current);
40
+ if (context === undefined)
41
+ delete all[target];
42
+ else
43
+ all[target] = context;
44
+ return `${JSON.stringify(all, null, 2)}\n`;
45
+ });
46
+ }
47
+ async function refresh(target) {
48
+ const fetched = await fetchReplyContext(target, { lookup });
49
+ if (!fetched.ok) {
50
+ logger.warn(`Could not read ${target} for a reply's context: ${fetched.reason}`);
51
+ return;
52
+ }
53
+ await write(target, fetched.context);
54
+ }
55
+ /** Forget a target, unless a post still replies to it. */
56
+ async function forget(target) {
57
+ if (!(target in readAll()))
58
+ return;
59
+ const stillAnswered = store.listAll().some((document) => replyTarget(document) === target);
60
+ if (!stillAnswered)
61
+ await write(target, undefined);
62
+ }
63
+ let chain = Promise.resolve();
64
+ function enqueue(task) {
65
+ chain = chain.then(task).catch((thrown) => {
66
+ logger.warn(`A reply context failed: ${thrown instanceof Error ? thrown.message : String(thrown)}`);
67
+ });
68
+ }
69
+ return {
70
+ handle(change) {
71
+ const before = targetOf(change.previous);
72
+ const after = targetOf(change.next);
73
+ // A scan rebuilds the index from files the contexts file sits beside, so
74
+ // it only fetches what that file has never held; an edit fetches a
75
+ // 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));
81
+ }
82
+ if (before !== undefined && before !== after)
83
+ enqueue(() => forget(before));
84
+ },
85
+ catchUp() {
86
+ const held = readAll();
87
+ const missing = new Set();
88
+ for (const document of store.listAll()) {
89
+ const target = replyTarget(document);
90
+ if (target !== undefined && !(target in held))
91
+ missing.add(target);
92
+ }
93
+ for (const target of missing)
94
+ enqueue(() => refresh(target));
95
+ },
96
+ read(target) {
97
+ return readAll()[target];
98
+ },
99
+ settled() {
100
+ return chain.then(ignore);
101
+ },
102
+ };
103
+ }
104
+ function targetOf(document) {
105
+ return document === undefined ? undefined : replyTarget(document);
106
+ }
107
+ /**
108
+ * The file's entries, each checked, since a person may have edited it by hand.
109
+ * An entry that is not a context is dropped rather than failing a render.
110
+ */
111
+ function parseContexts(text) {
112
+ let parsed;
113
+ try {
114
+ parsed = JSON.parse(text);
115
+ }
116
+ catch {
117
+ return {};
118
+ }
119
+ if (!isRecord(parsed))
120
+ return {};
121
+ const contexts = {};
122
+ for (const [target, value] of Object.entries(parsed)) {
123
+ if (!isRecord(value))
124
+ continue;
125
+ const author = isRecord(value['author']) ? value['author'] : undefined;
126
+ const authorName = stringOf(author?.['name']);
127
+ const authorUrl = webUrlOf(author?.['url']);
128
+ contexts[target] = {
129
+ url: target,
130
+ ...optional('name', stringOf(value['name'])),
131
+ ...optional('text', stringOf(value['text'])),
132
+ ...(authorName === undefined
133
+ ? {}
134
+ : { author: { name: authorName, ...optional('url', authorUrl) } }),
135
+ ...optional('published', stringOf(value['published'])),
136
+ };
137
+ }
138
+ return contexts;
139
+ }
140
+ function isRecord(value) {
141
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
142
+ }
143
+ function stringOf(value) {
144
+ return typeof value === 'string' && value !== '' ? value : undefined;
145
+ }
146
+ function webUrlOf(value) {
147
+ if (typeof value !== 'string')
148
+ return undefined;
149
+ try {
150
+ const url = new URL(value);
151
+ return url.protocol === 'http:' || url.protocol === 'https:' ? url.href : undefined;
152
+ }
153
+ catch {
154
+ return undefined;
155
+ }
156
+ }
157
+ function optional(key, value) {
158
+ return value === undefined ? {} : { [key]: value };
159
+ }
160
+ function ignore() {
161
+ // Deliberately empty: every failure is already logged against its target.
162
+ }
163
+ //# sourceMappingURL=reply-contexts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply-contexts.js","sourceRoot":"","sources":["../../src/webmention/reply-contexts.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/webmention/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAwB,MAAM,mBAAmB,CAAC;AAC1F,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAMzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE1E;;;;;;;;;;;;;;;;;GAiBG;AAEH,oEAAoE;AACpE,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,SAAS,cAAc,EAAE,CAAC;CAC1C;AAED,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,kDAAkD;AAClD,MAAM,WAAW,8BAA8B;IAC7C,0EAA0E;IAC1E,KAAK,EAAE,UAAU,CAAC;IAClB,+DAA+D;IAC/D,KAAK,EAAE,YAAY,CAAC;IACpB;;;OAGG;IACH,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,KAAK,GAAG,gBAAgB,CAAC,CAAC;IAC9F,0DAA0D;IAC1D,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACtC;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CAC5C;AAED,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IACrC;;;;;;;OAOG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;IAC1D;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAClE,kFAAkF;IAClF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,iDAAiD;AACjD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,8BAA8B,GACtC,iBAAiB,CAsKnB"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/webmention/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAwB,MAAM,mBAAmB,CAAC;AAC1F,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAMzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE1E;;;;;;;;;;;;;;;;;GAiBG;AAEH,oEAAoE;AACpE,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,SAAS,cAAc,EAAE,CAAC;CAC1C;AAED,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,kDAAkD;AAClD,MAAM,WAAW,8BAA8B;IAC7C,0EAA0E;IAC1E,KAAK,EAAE,UAAU,CAAC;IAClB,+DAA+D;IAC/D,KAAK,EAAE,YAAY,CAAC;IACpB;;;OAGG;IACH,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,KAAK,GAAG,gBAAgB,CAAC,CAAC;IAC9F,0DAA0D;IAC1D,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACtC;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CAC5C;AAED,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IACrC;;;;;;;OAOG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;IAC1D;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAClE,kFAAkF;IAClF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,iDAAiD;AACjD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,8BAA8B,GACtC,iBAAiB,CAsKnB"}
@@ -1,8 +1,9 @@
1
1
  import { readSiteSettings } from '../admin/settings.js';
2
+ import { replyTarget } from '../content/post-type.js';
2
3
  import { isFederatedDocument } from '../federation/article.js';
3
4
  import { absoluteUrl } from '../web/negotiate.js';
4
5
  import { discoverEndpoint, WEBMENTION_USER_AGENT } from './discovery.js';
5
- import { externalLinks } from './links.js';
6
+ import { externalLinks, externalTarget } from './links.js';
6
7
  import { verifyWebmention } from './receive.js';
7
8
  /**
8
9
  * Telling the pages a post links to that it links to them.
@@ -168,12 +169,18 @@ export function createWebmentionService(options) {
168
169
  },
169
170
  };
170
171
  }
171
- /** Every external page any of these versions of a post links to, in order. */
172
+ /**
173
+ * Every external page any of these versions of a post links to, in order: the
174
+ * post it replies to first, then the links in its body.
175
+ */
172
176
  function targetsOf(documents, baseUrl) {
173
177
  const targets = new Set();
174
178
  for (const document of documents) {
175
179
  if (document === undefined)
176
180
  continue;
181
+ const reply = externalTarget(replyTarget(document), baseUrl);
182
+ if (reply !== undefined)
183
+ targets.add(reply);
177
184
  for (const target of externalLinks(document.html, baseUrl))
178
185
  targets.add(target);
179
186
  }
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/webmention/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/webmention/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAKxD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhD;;;;;;;;;;;;;;;;;GAiBG;AAEH,oEAAoE;AACpE,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AAuEtC,iDAAiD;AACjD,MAAM,UAAU,uBAAuB,CACrC,OAAuC;IAEvC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACzC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC;IAEzC,gEAAgE;IAChE,MAAM,OAAO,GAAmB,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;IAEzE,4EAA4E;IAC5E,4EAA4E;IAC5E,qDAAqD;IACrD,IAAI,QAAQ,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEnD,0EAA0E;IAC1E,wDAAwD;IACxD,IAAI,KAAK,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEhD,SAAS,OAAO,CAAI,IAAsB;QACxC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACpC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,4EAA4E;IAC5E,SAAS,OAAO;QACd,OAAO,gBAAgB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC;IAC7D,CAAC;IAED,mEAAmE;IACnE,KAAK,UAAU,IAAI,CAAC,IAAY,EAAE,MAAc,EAAE,MAAc;QAC9D,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,wEAAwE;YACxE,2CAA2C;YAC3C,OAAO,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;gBACrC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,mCAAmC;oBACnD,MAAM,EAAE,8CAA8C;oBACtD,YAAY,EAAE,qBAAqB;iBACpC;gBACD,IAAI,EAAE,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;gBACxD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,eAAe,CAAC;aAC7C,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,KAAK,GAAG,GAAG,QAAQ,aAAa,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAChE,MAAM,CAAC,IAAI,CAAC,mCAAmC,MAAM,KAAK,KAAK,EAAE,CAAC,CAAC;gBACnE,OAAO,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjE,CAAC;YAED,OAAO,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,MAAM,EAAE,CAAC;YAChB,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;YAChC,MAAM,CAAC,IAAI,CAAC,mCAAmC,MAAM,KAAK,KAAK,EAAE,CAAC,CAAC;YACnE,OAAO,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,SAAS,MAAM,CACb,IAAY,EACZ,MAAc,EACd,MAAc,EACd,QAAuB,EACvB,MAA4B,EAC5B,KAAoB;QAEpB,OAAO,KAAK,CAAC,oBAAoB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACvF,CAAC;IAED,6DAA6D;IAC7D,KAAK,UAAU,OAAO,CACpB,IAAY,EACZ,MAAc,EACd,OAA0B;QAE1B,MAAM,QAAQ,GAAqB,EAAE,CAAC;QACtC,KAAK,MAAM,MAAM,IAAI,OAAO;YAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAC9E,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO;QACL,MAAM,CAAC,MAAM;YACX,kEAAkE;YAClE,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM;gBAAE,OAAO;YACrC,IAAI,CAAC,OAAO,EAAE;gBAAE,OAAO;YAEvB,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC;YAChD,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO;YAEnC,yEAAyE;YACzE,uDAAuD;YACvD,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YACjD,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC/C,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW;gBAAE,OAAO;YAEvC,uEAAuE;YACvE,yEAAyE;YACzE,sEAAsE;YACtE,uBAAuB;YACvB,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAC/D,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAC1E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAEjC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAe,EAAE,EAAE;gBAC/E,MAAM,CAAC,IAAI,CAAC,wBAAwB,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC3D,CAAC,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,IAAI;YACb,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACzC,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YAE7C,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAC/D,IAAI,CAAC,OAAO,EAAE;gBAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;YAElD,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAEtD,OAAO,MAAM,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBAChC,IAAI;gBACJ,MAAM;gBACN,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC;aAC3C,CAAC,CAAC,CAAC;QACN,CAAC;QAED,OAAO,CAAC,QAAQ;YACd,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAgC,EAAE;gBACnE,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC;wBACrC,QAAQ;wBACR,OAAO;wBACP,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,OAAO,EAAE,MAAM,CAAC,cAAc;wBAC9B,8DAA8D;wBAC9D,gEAAgE;wBAChE,gEAAgE;wBAChE,kBAAkB;wBAClB,OAAO,EAAE,OAAO,CAAC,aAAa;wBAC9B,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE;wBACjB,MAAM;qBACP,CAAC,CAAC;oBAEH,OAAO,OAAO,CAAC;gBACjB,CAAC;gBAAC,OAAO,MAAM,EAAE,CAAC;oBAChB,gEAAgE;oBAChE,mEAAmE;oBACnE,mDAAmD;oBACnD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;oBACjC,MAAM,CAAC,IAAI,CAAC,qBAAqB,QAAQ,CAAC,MAAM,0BAA0B,MAAM,EAAE,CAAC,CAAC;oBACpF,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;gBACzC,CAAC;YACH,CAAC,CAAC,CAAC;YACH,QAAQ,GAAG,OAAO,CAAC;YACnB,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,OAAO;YACL,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrD,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,SAA4C,EAAE,OAAe;IAC9E,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,QAAQ,KAAK,SAAS;YAAE,SAAS;QACrC,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;QAC7D,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC5C,KAAK,MAAM,MAAM,IAAI,aAAa,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClF,CAAC;IAED,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AACtB,CAAC;AAED,qEAAqE;AACrE,SAAS,QAAQ,CAAC,QAA8B,EAAE,GAAS;IACzD,OAAO,QAAQ,KAAK,SAAS,IAAI,mBAAmB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,UAAU,CAAC,KAAmB,EAAE,IAAY;IACnD,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,OAAO,KAAK,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC1E,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,MAAM;IACb,sEAAsE;IACtE,sDAAsD;AACxD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekity/cms",
3
- "version": "0.5.0",
3
+ "version": "0.7.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,33 +28,33 @@
28
28
  "LICENSE"
29
29
  ],
30
30
  "dependencies": {
31
- "@fedify/fedify": "^2.3.6",
32
- "@fedify/hono": "^2.3.6",
33
- "@fedify/vocab": "^2.3.6",
31
+ "@fedify/fedify": "^2.3.7",
32
+ "@fedify/hono": "^2.3.7",
33
+ "@fedify/vocab": "^2.3.7",
34
34
  "@hono/node-server": "^2.1.1",
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.7",
38
+ "hono": "^4.13.8",
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.9",
42
+ "nodemailer": "^10.0.10",
43
43
  "nunjucks": "^3.2.4",
44
44
  "sharp": "^0.35.4"
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.6",
49
+ "@fedify/cli": "2.3.7",
50
50
  "@types/markdown-it-footnote": "^3.0.4",
51
- "@types/node": "^26.4.1",
52
- "@types/nodemailer": "^8.0.1",
51
+ "@types/node": "^26.6.2",
52
+ "@types/nodemailer": "^8.0.2",
53
53
  "@types/nunjucks": "^3.2.6",
54
54
  "codemirror": "^6.0.2",
55
55
  "esbuild": "^0.28.2",
56
56
  "highlight.js": "11.12.0",
57
- "tsx": "^4.23.13",
57
+ "tsx": "^4.23.15",
58
58
  "typescript": "^7.0.2"
59
59
  },
60
60
  "scripts": {
@@ -262,7 +262,9 @@ person on an author archive.
262
262
  What the bio prints: a round `u-photo` at 50px when they have an avatar,
263
263
  "Written by" and their name as a `p-name u-url` linked `rel="author me"` to
264
264
  their archive, then `p-job-title` and `p-locality` when the profile says, then
265
- their `p-note` and their `rel="me"` links as a `ul.hlist.bio-links`. Each of
265
+ their `p-note` and their `rel="me"` links as a `ul.hlist.bio-links` — each
266
+ link's `rel` is on it ready to print, `me` first and then whatever else the
267
+ Links box typed. Each of
266
268
  those is printed only when the profile says it, so a profile holding a name
267
269
  alone prints a name alone. A name this site has no account for is printed
268
270
  unlinked, because the file still said somebody wrote this.
@@ -834,7 +836,7 @@ A site stores its menus by name in `content/_data/site.json`:
834
836
  ],
835
837
  "footer": [
836
838
  { "label": "Colophon", "url": "/colophon/" },
837
- { "label": "Mastodon", "url": "https://example.social/@me", "me": true }
839
+ { "label": "Mastodon", "url": "https://example.social/@me", "rel": "me" }
838
840
  ]
839
841
  }
840
842
  }
@@ -882,14 +884,17 @@ rather than failing to load it.
882
884
 
883
885
  ### One item
884
886
 
885
- Each item is `{ label, url, current }`, plus `me: true` on a link that should
886
- carry `rel="me"`. `url` is a site-root path or an absolute URL for somewhere
887
- else, so put it through the `url` filter and a site served from a subdirectory
888
- still links correctly. `current` is true for the item whose path is the one
889
- being rendered, comparing without the trailing slash; an item pointing off the
890
- site is never current. `me` is for the IndieWeb's identity check: Mastodon
891
- verifies a link on a profile by looking for a `rel="me"` link back, so a footer
892
- link to a profile marked `me` is what makes the tick appear.
887
+ Each item is `{ label, url, current }`, plus `rel` on a link that carries `rel`
888
+ values. `url` is a site-root path or an absolute URL for somewhere else, so put
889
+ it through the `url` filter and a site served from a subdirectory still links
890
+ correctly. `current` is true for the item whose path is the one being rendered,
891
+ comparing without the trailing slash; an item pointing off the site is never
892
+ current. `rel` is one string holding every value the line carried, already
893
+ lower case and each said once — print it as the whole attribute,
894
+ `rel="{{ item.rel }}"`, rather than building one of your own. `me` is the value
895
+ most menus have, for the IndieWeb's identity check: Mastodon verifies a link on
896
+ a profile by looking for a `rel="me"` link back, so a footer link to a profile
897
+ marked `me` is what makes the tick appear.
893
898
 
894
899
  ### Where this theme prints them
895
900
 
@@ -920,6 +925,16 @@ account: it used to print one `rel="me"` link per entry of `siteAuthor.links`,
920
925
  which meant one nominated user's links stood for the site and nobody else's
921
926
  appeared at all.
922
927
 
928
+ Every menu reads the same: a link in one is the colour, the underline and the
929
+ size of a link in the page's prose, in the sans heading font a `nav` is set in
930
+ (TASK-111). A menu is navigation somebody is meant to use rather than a
931
+ footnote, so none of them is set smaller than the words around it, and the same
932
+ goes for the `rel="me"` links `partials/bio.njk` prints under a post. The two
933
+ links that read as plain text instead are the site title and
934
+ `a.header-link-home`, which are the page saying where it is rather than
935
+ somewhere to go, and the stylesheet names those two rather than reaching for
936
+ every link that happens to sit in a `<header>`.
937
+
923
938
  `menus.primary` is the whole of the site menu, in the order the Navigation
924
939
  screen names it. Both areas are declared in this theme's `theme.json`, which is
925
940
  what puts them on `/admin/navigation` with those labels; a theme that renders a
@@ -39,7 +39,9 @@
39
39
  `pagination`, and the posts page is a listing carrying a page's front
40
40
  matter, so it is a website like every other listing. -#}
41
41
  {% set metaDescription = description or summary or site.tagline %}
42
- {% set metaTitle = title or site.title %}
42
+ {#- A note has no title, and is named here by its first words. -#}
43
+ {% set pageTitle = title or label %}
44
+ {% set metaTitle = pageTitle or site.title %}
43
45
  {% set metaUrl = (page.url or "/") | absoluteUrl %}
44
46
  {% set metaImage = image or site.avatar %}
45
47
  {% set isEntry = (type == "post" or type == "page") and not pagination %}
@@ -48,7 +50,7 @@
48
50
  <head>
49
51
  <meta charset="utf-8">
50
52
  <meta name="viewport" content="width=device-width, initial-scale=1">
51
- <title>{% block title %}{% if title %}{{ title }} &middot; {% endif %}{{ site.title }}{% endblock %}</title>
53
+ <title>{% block title %}{% if pageTitle %}{{ pageTitle }} &middot; {% endif %}{{ site.title }}{% endblock %}</title>
52
54
  {% if metaDescription %}
53
55
  <meta name="description" content="{{ metaDescription }}">
54
56
  {% endif %}
@@ -58,7 +60,7 @@
58
60
  {{ feeds.feedLinks("/", site.title) }}
59
61
  {{ feeds.commentsFeedLink("/comments/feed/", site.title + " comments") }}
60
62
  {% if commentsFeed %}
61
- {{ feeds.commentsFeedLink(commentsFeed, "Comments on: " + title) }}
63
+ {{ feeds.commentsFeedLink(commentsFeed, "Comments on: " + pageTitle) }}
62
64
  {% endif %}
63
65
  {% if activityStreams %}
64
66
  <link rel="alternate" type="application/activity+json" href="{{ activityStreams }}">
@@ -23,9 +23,17 @@
23
23
  {% block content %}
24
24
  {% set entryUrl = page.url or url %}
25
25
  <article class="blog-post h-entry">
26
+ {#- A post with no name of its own (a note, or a reply without a title) is
27
+ its words, so it opens on them rather than on an empty heading. -#}
28
+ {% if named %}
26
29
  <header>
27
30
  <h1 class="p-name">{{ title }}</h1>
28
31
  </header>
32
+ {% endif %}
33
+
34
+ {#- A reply cites the post it answers, whose URL is also the link its
35
+ webmention points a receiver at. -#}
36
+ {% include "partials/reply-context.njk" %}
29
37
 
30
38
  <section class="e-content">
31
39
  {{ content | safe }}
@@ -37,8 +37,10 @@
37
37
  <div class="search-results">
38
38
  {% for post in posts %}
39
39
  <article class="search-result h-entry">
40
- <h2 class="feed-title p-name">
41
- <a href="{{ post.url | url }}" class="u-url">{{ post.title }}</a>
40
+ {#- A post with no name of its own has none to claim, so its first words
41
+ link it without being marked up as one. -#}
42
+ <h2 class="feed-title{% if post.named %} p-name{% endif %}">
43
+ <a href="{{ post.url | url }}" class="u-url">{{ post.label }}</a>
42
44
  </h2>
43
45
  {% if post.snippet %}
44
46
  <p class="search-snippet">{{ post.snippet | safe }}</p>
@@ -29,6 +29,10 @@
29
29
  otherwise. An author archive sets "Posts by", because the card there heads a
30
30
  list of somebody's writing rather than crediting one piece of it.
31
31
 
32
+ A link's `rel` always holds `me` — the CMS puts it there whether or not the
33
+ Links box typed it — followed by whatever else that line carried, so this
34
+ prints one attribute rather than one of its own beside one of theirs.
35
+
32
36
  The `p-note` and the `rel="me"` links are printed wherever the card is, which
33
37
  is what `bioProfile` used to ask for on an author archive alone. An entry
34
38
  left that switch unset because the page footer carried the site's identity
@@ -62,7 +66,7 @@
62
66
  {%- if bioAuthor.links.length %}
63
67
  <ul class="hlist bio-links">
64
68
  {%- for link in bioAuthor.links %}
65
- <li><a class="u-url" rel="me" href="{{ link.href }}">{{ link.label }}</a></li>
69
+ <li><a class="u-url" rel="{{ link.rel }}" href="{{ link.href }}">{{ link.label }}</a></li>
66
70
  {%- endfor %}
67
71
  </ul>
68
72
  {%- endif %}
@@ -17,15 +17,17 @@
17
17
  which of a page's menus this one is. Two navs with no labels are two navs
18
18
  called "navigation".
19
19
 
20
- An item marked `me` carries `rel="me"`, which is how Mastodon and the rest of
21
- the IndieWeb verify that the site and the profile it links belong to the same
22
- person: the profile links back, and the pair is the proof.
20
+ An item's `rel` is whatever `rel` values its line carried, already lower case
21
+ and each said once, so it is printed as one attribute and nothing is joined
22
+ here. `me` is the one most menus want: it is how Mastodon and the rest of the
23
+ IndieWeb verify that the site and the profile it links belong to the same
24
+ person — the profile links back, and the pair is the proof.
23
25
  #}
24
26
  {% macro list(items, label) %}{% if items.length %}
25
27
  <nav class="site-nav" aria-label="{{ label }}">
26
28
  <ul class="hlist">
27
29
  {% for item in items %}
28
- <li><a href="{{ item.url | url }}"{% if item.me %} rel="me"{% endif %}{% if item.current %} class="is-current" aria-current="page"{% endif %}>{{ item.label }}</a></li>
30
+ <li><a href="{{ item.url | url }}"{% if item.rel %} rel="{{ item.rel }}"{% endif %}{% if item.current %} class="is-current" aria-current="page"{% endif %}>{{ item.label }}</a></li>
29
31
  {% endfor %}
30
32
  </ul>
31
33
  </nav>
@@ -2,10 +2,11 @@
2
2
  The feed a listing is made of: `h-feed` of `h-entry` items, as the source
3
3
  design lists them (decision-16).
4
4
 
5
- Expects `posts`. Each entry prints its title as a linked `p-name`, its
6
- `summary` — the very line the feeds publish — as a `p-summary` cut to about
7
- 280 characters, a Continue reading link, its publish date and the categories
8
- it is filed under. Tags are deliberately not here: an entry's tags belong
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
9
10
  under the entry, and a feed of twenty posts listing everyone's would be a
10
11
  wall of links rather than a list of writing.
11
12
 
@@ -24,6 +25,12 @@
24
25
  {% endif %}
25
26
  <article class="feed-item h-entry">
26
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 %}
27
34
  <{{ feedTitleTag }} class="feed-title p-name">
28
35
  <a href="{{ post.url | url }}" class="u-url">{{ post.title }}</a>
29
36
  </{{ feedTitleTag }}>
@@ -38,8 +45,13 @@
38
45
  <p class="feed-more">
39
46
  <a href="{{ post.url | url }}" aria-label="Continue reading: {{ post.title }}">Continue reading<span aria-hidden="true"> &rarr;</span></a>
40
47
  </p>
48
+ {% endif %}
41
49
  <div class="feed-meta">
42
- {% if post.date %}
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 %}
43
55
  <p>
44
56
  <time class="feed-date dt-published" datetime="{{ post.date | date("iso") }}">
45
57
  {{ post.date | date }}
@@ -0,0 +1,29 @@
1
+ {#
2
+ The post a reply answers, cited in the reply (TASK-123): an embedded
3
+ `u-in-reply-to h-cite` that always carries the target's URL, so a parser
4
+ reads what this post answers even when nothing more is known about it.
5
+
6
+ `replyContext` is what the target said about itself when the reply was saved
7
+ or synced: its name, a short excerpt, its author and its date, each only when
8
+ it said so. It is somebody else's words, so every piece is printed through
9
+ autoescaping and none of it with `safe`.
10
+ #}
11
+ {% if inReplyTo %}
12
+ <div class="reply-context u-in-reply-to h-cite">
13
+ <p class="small">In reply to
14
+ {%- if replyContext.name %} <a class="u-url p-name" href="{{ inReplyTo }}">{{ replyContext.name }}</a>
15
+ {%- else %} <a class="u-url" href="{{ inReplyTo }}">{{ inReplyTo }}</a>
16
+ {%- endif %}
17
+ {%- if replyContext.author %} by <span class="p-author h-card">
18
+ {%- if replyContext.author.url %}<a class="u-url p-name" href="{{ replyContext.author.url }}">{{ replyContext.author.name }}</a>
19
+ {%- else %}<span class="p-name">{{ replyContext.author.name }}</span>{% endif -%}
20
+ </span>
21
+ {%- endif %}
22
+ {%- if replyContext.published %} on <time class="dt-published" datetime="{{ replyContext.published | date("iso") }}">{{ replyContext.published | date }}</time>
23
+ {%- endif -%}
24
+ </p>
25
+ {% if replyContext.text %}
26
+ <blockquote class="p-content">{{ replyContext.text }}</blockquote>
27
+ {% endif %}
28
+ </div>
29
+ {% endif %}
@@ -299,14 +299,29 @@ a:focus-visible {
299
299
  color: var(--color-primary);
300
300
  }
301
301
 
302
- header a,
303
- header a:visited {
302
+ /* The two links that are the page saying where it is rather than somewhere to
303
+ go: the site title at the root and the small link home everywhere else. Both
304
+ read as plain text, in the heading font the rules below give them.
305
+
306
+ Named rather than reached for through the element they sit in (TASK-111). A
307
+ bare `header a` also caught the site menu, which is navigation somebody is
308
+ meant to use, and every link inside a post's own `<header>`. The `:visited`
309
+ halves are here because `a:visited` outweighs a bare class, and the hover
310
+ and focus halves because `a:focus-visible` outweighs one too: without them
311
+ these two would take the outline rather than the flourish. */
312
+
313
+ .main-heading a,
314
+ .main-heading a:visited,
315
+ .header-link-home,
316
+ .header-link-home:visited {
304
317
  color: var(--color-text);
305
318
  text-decoration: none;
306
319
  }
307
320
 
308
- header a:hover,
309
- header a:focus {
321
+ .main-heading a:hover,
322
+ .main-heading a:focus,
323
+ .header-link-home:hover,
324
+ .header-link-home:focus {
310
325
  background-color: var(--color-primary);
311
326
  color: var(--color-body);
312
327
  text-decoration: none;
@@ -618,10 +633,13 @@ pre code {
618
633
 
619
634
  /* The site menu, which the header carries on every page (TASK-105). At the
620
635
  root the header is the site title with the tagline under it, and the menu
621
- is a line of its own under that. */
636
+ is a line of its own under that.
637
+
638
+ No size of its own (TASK-111): a menu is navigation somebody is meant to
639
+ use rather than a footnote, so it reads at the page's size, like the footer
640
+ menu, which never had one. */
622
641
  .global-header .site-nav {
623
642
  margin-top: var(--spacing-2);
624
- font-size: var(--fontSize-0);
625
643
  }
626
644
 
627
645
  /* Everywhere else the header is the small link home, and the menu sits beside
@@ -690,12 +708,12 @@ pre code {
690
708
  font-style: italic;
691
709
  }
692
710
 
693
- /* The links the person calls their own, under the credit: a horizontal list,
694
- small, in the heading font. The site menu used to share this rule; it is in
695
- the header now (TASK-105) and the bio carries nobody but the person. */
711
+ /* The links the person calls their own, under the credit: a horizontal list in
712
+ the heading font, at the page's size like every other nav (TASK-111). The
713
+ site menu used to share this rule; it is in the header now (TASK-105) and
714
+ the bio carries nobody but the person. */
696
715
  .bio-links {
697
716
  margin-top: var(--spacing-2);
698
- font-size: var(--fontSize-0);
699
717
  }
700
718
 
701
719
  .bio-avatar {