@riebeckite/plugin-diff 0.0.15 → 0.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -99,10 +99,9 @@ function initDiffHistory() {
99
99
  }
100
100
  function initDiffHistoryRoot(root) {
101
101
  const payload = readPayload(root);
102
- if (!payload || payload.revisions.length === 0) return;
103
- const revisions = new Map(
104
- payload.revisions.map((revision) => [revision.hash, revision])
105
- );
102
+ if (!payload) return;
103
+ let revisions = revisionsMap(payload.revisions ?? []);
104
+ let revisionsRequest = null;
106
105
  const fromSelect = root.querySelector(
107
106
  "[data-rr-diff-from]"
108
107
  );
@@ -115,23 +114,74 @@ function initDiffHistoryRoot(root) {
115
114
  button.addEventListener("click", () => {
116
115
  const toHash = button.dataset.rrDiffSelect;
117
116
  if (!toHash) return;
118
- const diff = createDiff(revisions, fromSelect.value, toHash);
119
- if (!diff) return;
120
- fromSelect.value = diff.from?.hash ?? "";
121
- toSelect.value = diff.to.hash;
122
- updateSelectedCommit(root, diff.to.hash);
123
- renderPanel(panel, diff);
117
+ void updateDiff({
118
+ root,
119
+ panel,
120
+ getRevisions: () => revisions,
121
+ setRevisions: (loaded) => {
122
+ revisions = loaded;
123
+ },
124
+ load: () => {
125
+ revisionsRequest ??= loadRevisions(payload.path);
126
+ return revisionsRequest;
127
+ },
128
+ fromHash: fromSelect.value,
129
+ toHash,
130
+ fromSelect,
131
+ toSelect
132
+ });
124
133
  });
125
134
  }
126
135
  const updateFromSelects = () => {
127
- const diff = createDiff(revisions, fromSelect.value, toSelect.value);
128
- if (!diff) return;
129
- updateSelectedCommit(root, diff.to.hash);
130
- renderPanel(panel, diff);
136
+ void updateDiff({
137
+ root,
138
+ panel,
139
+ getRevisions: () => revisions,
140
+ setRevisions: (loaded) => {
141
+ revisions = loaded;
142
+ },
143
+ load: () => {
144
+ revisionsRequest ??= loadRevisions(payload.path);
145
+ return revisionsRequest;
146
+ },
147
+ fromHash: fromSelect.value,
148
+ toHash: toSelect.value,
149
+ fromSelect,
150
+ toSelect
151
+ });
131
152
  };
132
153
  fromSelect.addEventListener("change", updateFromSelects);
133
154
  toSelect.addEventListener("change", updateFromSelects);
134
155
  }
156
+ async function updateDiff(input) {
157
+ const { root, panel, fromHash, toHash, fromSelect, toSelect } = input;
158
+ const token = `${fromHash}
159
+ ${toHash}`;
160
+ root.dataset.rrDiffPending = token;
161
+ const loaded = await input.load();
162
+ if (loaded) input.setRevisions(loaded);
163
+ if (root.dataset.rrDiffPending !== token) return;
164
+ const diff = createDiff(input.getRevisions(), fromHash, toHash);
165
+ if (!diff) return;
166
+ fromSelect.value = diff.from?.hash ?? "";
167
+ toSelect.value = diff.to.hash;
168
+ updateSelectedCommit(root, diff.to.hash);
169
+ renderPanel(panel, diff);
170
+ }
171
+ async function loadRevisions(path) {
172
+ if (!path) return null;
173
+ try {
174
+ const response = await fetch(path);
175
+ if (!response.ok) return null;
176
+ const payload = await response.json();
177
+ return revisionsMap(payload.revisions ?? []);
178
+ } catch {
179
+ return null;
180
+ }
181
+ }
182
+ function revisionsMap(revisions) {
183
+ return new Map(revisions.map((revision) => [revision.hash, revision]));
184
+ }
135
185
  function createDiff(revisions, fromHash, toHash) {
136
186
  const to = revisions.get(toHash);
137
187
  if (!to) return null;
@@ -165,15 +215,13 @@ function updateSelectedCommit(root, hash) {
165
215
  }
166
216
  }
167
217
  function renderPanel(panel, diff) {
168
- const fromLabel = diff.from?.shortHash ?? "Beginning";
169
- panel.innerHTML = `<details class="rr-diff-history__diff" data-rr-diff-rendered open>
170
- <summary class="rr-diff-history__diff-head">${escapeHtml(fromLabel)} → ${escapeHtml(diff.to.shortHash)}</summary>
218
+ panel.innerHTML = `<div class="rr-diff-history__diff" data-rr-diff-rendered>
171
219
  <div class="rr-diff-history__table-wrap">
172
220
  <table class="rr-diff-history__table">
173
221
  <tbody>${diff.lines.map(renderLine).join("")}</tbody>
174
222
  </table>
175
223
  </div>
176
- </details>`;
224
+ </div>`;
177
225
  }
178
226
  function renderLine(line) {
179
227
  const prefix = line.type === "added" ? "+" : line.type === "removed" ? "-" : " ";
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // index.ts
2
2
  import {
3
+ appendContentBodySlot,
3
4
  createClientEntry,
4
5
  createStyleAsset,
5
6
  definePlugin
@@ -53,15 +54,13 @@ function renderDiffViewer({
53
54
  </div>`;
54
55
  }
55
56
  function renderDiffPanel(diff2) {
56
- const fromLabel = diff2.from?.shortHash ?? "Beginning";
57
- return `<details class="rr-diff-history__diff" data-rr-diff-rendered open>
58
- <summary class="rr-diff-history__diff-head">${escapeHtml(fromLabel)} → ${escapeHtml(diff2.to.shortHash)}</summary>
57
+ return `<div class="rr-diff-history__diff" data-rr-diff-rendered>
59
58
  <div class="rr-diff-history__table-wrap">
60
59
  <table class="rr-diff-history__table">
61
60
  <tbody>${diff2.lines.map((line) => renderDiffLine({ line })).join("")}</tbody>
62
61
  </table>
63
62
  </div>
64
- </details>`;
63
+ </div>`;
65
64
  }
66
65
  function renderRevisionSelect(kind, history, value) {
67
66
  const emptyOption = kind === "from" ? `<option value="">Beginning</option>` : "";
@@ -74,19 +73,17 @@ function renderRevisionSelect(kind, history, value) {
74
73
  function renderDiffHistory(input) {
75
74
  const history = input.revisions;
76
75
  const selected = input.selected;
77
- const payload = JSON.stringify({ revisions: input.revisions }).replace(
78
- /</g,
79
- "\\u003c"
80
- );
76
+ const payloadPath = input.payloadPath;
77
+ if (history.length === 0 || !selected) return "";
81
78
  return `<section class="rr-diff-history" data-rr-diff-history>
82
- <details class="rr-diff-history__panel" open>
79
+ <details class="rr-diff-history__panel">
83
80
  <summary class="rr-diff-history__header">
84
81
  <h2 class="rr-diff-history__title">History</h2>
85
82
  <span class="rr-diff-history__header-meta"><span class="rr-diff-history__count">${history.length} changes</span><span class="rr-diff-history__toggle-label rr-diff-history__toggle-label--open">Collapse</span><span class="rr-diff-history__toggle-label rr-diff-history__toggle-label--closed">Expand</span><span class="rr-diff-history__toggle" aria-hidden="true"><svg class="rr-diff-history__toggle-icon" viewBox="0 0 16 16" width="16" height="16" focusable="false"><path d="M5.2 3.4 10.8 8l-5.6 4.6" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"/></svg></span></span>
86
83
  </summary>
87
- ${history.length === 0 || !selected ? renderEmptyState() : renderContent(history, selected)}
84
+ ${renderContent(history, selected)}
88
85
  </details>
89
- <script type="application/json" data-rr-diff-history-data>${payload}</script>
86
+ ${payloadPath ? `<script type="application/json" data-rr-diff-history-data>${JSON.stringify({ path: payloadPath }).replace(/</g, "\\u003c")}</script>` : ""}
90
87
  </section>`;
91
88
  }
92
89
  function renderContent(history, selected) {
@@ -97,9 +94,6 @@ function renderContent(history, selected) {
97
94
  ${renderDiffViewer({ history, selected })}
98
95
  </div>`;
99
96
  }
100
- function renderEmptyState() {
101
- return `<p class="rr-diff-history__empty">No Git history is available for this article.</p>`;
102
- }
103
97
  function renderRevisionButton(revision, selected) {
104
98
  return `<li class="rr-diff-history__item">
105
99
  <button class="rr-diff-history__commit" type="button" data-rr-diff-select="${escapeHtml(revision.hash)}" aria-pressed="${selected}">
@@ -396,33 +390,55 @@ function diff(options = {}) {
396
390
  let api;
397
391
  return definePlugin({
398
392
  name: "diff",
393
+ order: 200,
399
394
  processedContentCache: {
400
- version: "diff-v2",
395
+ version: "diff-v3",
401
396
  dependencyMode: "unsafe"
402
397
  },
403
398
  options,
404
399
  assets: ui.enabled === false ? [] : [createStyleAsset("diff")],
405
400
  clientEntries: ui.enabled === false ? [] : [createClientEntry("diff", "initDiffHistory")],
406
- onPostProcessed: async (context) => {
401
+ onManifestCreated: async (context) => {
407
402
  if (ui.enabled === false) return;
408
403
  api ??= createPostDiffApi({
409
404
  ...options,
410
405
  cwd: options.cwd ?? context.config?.content.directory
411
406
  });
412
- const filePath = resolvePostFilePath(context);
413
- const history = (await api.getHistory(filePath)).slice(
414
- 0,
415
- ui.maxRevisions
416
- );
417
- const revisions = await getMarkdownRevisions(api, filePath, history);
418
- const selected = await api.getCurrentDiff(filePath);
419
- context.content.html += renderDiffHistory({
420
- revisions,
421
- selected
422
- });
407
+ for (const entry of context.manifest.discoverableEntries) {
408
+ const filePath = resolvePostFilePath({
409
+ slug: entry.slug,
410
+ contentIndex: context.contentIndex
411
+ });
412
+ const history = (await api.getHistory(filePath)).slice(
413
+ 0,
414
+ ui.maxRevisions
415
+ );
416
+ const revisions = await getMarkdownRevisions(api, filePath, history);
417
+ if (revisions.length === 0) continue;
418
+ const selected = await api.getCurrentDiff(filePath);
419
+ if (!selected) continue;
420
+ const payloadPath = diffPayloadPath(entry.slug);
421
+ context.output.emit({
422
+ path: payloadPath,
423
+ content: JSON.stringify({ revisions }).replace(/</g, "\\u003c"),
424
+ dependencies: [{ type: "content", slug: entry.slug }]
425
+ });
426
+ appendContentBodySlot(
427
+ entry,
428
+ "article.footer",
429
+ renderDiffHistory({
430
+ revisions,
431
+ selected,
432
+ payloadPath: `/${payloadPath}`
433
+ })
434
+ );
435
+ }
423
436
  }
424
437
  });
425
438
  }
439
+ function diffPayloadPath(slug) {
440
+ return `_riebeckite/diff/${Buffer.from(slug).toString("base64url")}.json`;
441
+ }
426
442
  function createPostDiffApi(options = {}) {
427
443
  const reader = new GitMarkdownHistoryReader(options);
428
444
  return {
@@ -2,5 +2,6 @@ import type { MarkdownRevision, PostDiff } from "../types.js";
2
2
  export type DiffHistoryProps = {
3
3
  revisions: MarkdownRevision[];
4
4
  selected: PostDiff | null;
5
+ payloadPath?: string;
5
6
  };
6
7
  export declare function renderDiffHistory(input: DiffHistoryProps): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riebeckite/plugin-diff",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -21,12 +21,12 @@
21
21
  "./style.css": "./style.css"
22
22
  },
23
23
  "dependencies": {
24
- "@riebeckite/core": "0.0.15"
24
+ "@riebeckite/core": "0.0.17"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/node": "^24.5.2",
28
28
  "tsx": "^4.22.4",
29
- "@riebeckite/test": "0.0.15"
29
+ "@riebeckite/test": "0.0.17"
30
30
  },
31
31
  "publishConfig": {
32
32
  "access": "public"
package/style.css CHANGED
@@ -1,5 +1,5 @@
1
1
  .rr-diff-history {
2
- margin-block: 4rem 2rem;
2
+ margin-block-start: var(--rb-space-6, 3rem);
3
3
  border-block-start: 1px solid
4
4
  var(--rb-color-border, color-mix(in srgb, currentColor 18%, transparent));
5
5
  padding-block-start: 1.5rem;
@@ -183,7 +183,6 @@
183
183
  }
184
184
 
185
185
  .rr-diff-history__commit:focus-visible,
186
- .rr-diff-history__diff-head:focus-visible,
187
186
  .rr-diff-history__controls select:focus-visible {
188
187
  outline: 2px solid var(--rb-color-accent, #f66620);
189
188
  outline-offset: 2px;
@@ -222,39 +221,16 @@
222
221
  var(--rb-color-border, color-mix(in srgb, currentColor 18%, transparent));
223
222
  }
224
223
 
225
- .rr-diff-history__diff-head {
226
- display: flex;
227
- align-items: center;
228
- gap: 0.5rem;
229
- border-block-end: 1px solid
230
- var(--rb-color-border, color-mix(in srgb, currentColor 18%, transparent));
231
- padding: 0.625rem 0.75rem;
232
- font-family: var(
233
- --rb-font-mono,
234
- ui-monospace,
235
- SFMono-Regular,
236
- Consolas,
237
- monospace
238
- );
239
- font-size: 0.8125rem;
240
- cursor: pointer;
241
- user-select: none;
242
- }
243
-
244
- .rr-diff-history__diff-head::marker {
245
- color: var(
246
- --rb-color-muted,
247
- color-mix(in srgb, currentColor 62%, transparent)
248
- );
249
- }
250
-
251
224
  .rr-diff-history__table-wrap {
252
225
  overflow-x: auto;
253
226
  }
254
227
 
255
228
  .rr-diff-history__table {
229
+ display: table;
256
230
  width: 100%;
257
231
  min-width: 42rem;
232
+ margin-block: 0;
233
+ overflow-x: visible;
258
234
  border-collapse: collapse;
259
235
  font-family: var(
260
236
  --rb-font-mono,
@@ -301,15 +277,6 @@
301
277
  background: color-mix(in srgb, currentColor 2%, transparent);
302
278
  }
303
279
 
304
- .rr-diff-history__empty {
305
- margin: 0;
306
- color: var(
307
- --rb-color-muted,
308
- color-mix(in srgb, currentColor 62%, transparent)
309
- );
310
- font-size: 0.9375rem;
311
- }
312
-
313
280
  @media (max-width: 720px) {
314
281
  .rr-diff-history__layout {
315
282
  grid-template-columns: 1fr;
@@ -322,6 +289,16 @@
322
289
  }
323
290
 
324
291
  .rr-diff-history__header {
325
- align-items: flex-start;
292
+ align-items: center;
293
+ flex-wrap: nowrap;
294
+ }
295
+
296
+ .rr-diff-history__title {
297
+ min-width: 0;
298
+ }
299
+
300
+ .rr-diff-history__header-meta {
301
+ flex: none;
302
+ white-space: nowrap;
326
303
  }
327
304
  }