@leftoff/cli 0.9.17 → 0.9.18-beta.10

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/ui/what-it-did.js CHANGED
@@ -5,6 +5,7 @@
5
5
  // app.js) so they can be checked without a browser.
6
6
  import { icon } from './icons.js'
7
7
  import { diffBlocks, splitPath } from './diff-view.js'
8
+ import { fileScopeSegHtml, scopeTagHtml, unreadableLines } from './semdiff.js' // 2026-11-03 This session · Whole folder, the walkthrough's own rule
8
9
 
9
10
  const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]))
10
11
  const plural = (n, w) => n + ' ' + w + (n === 1 ? '' : 's')
@@ -63,12 +64,12 @@ export function fileRowHtml(f, ui, sid) {
63
64
  const bodyId = 'wid-f-' + esc(encodeURIComponent(f.path).replace(/%/g, '_'))
64
65
  const bar = '<span class="gd-bar" aria-hidden="true">' + diffBlocks(f.add, f.del).map((b) => '<i class="gd-b' + b + '"></i>').join('') + '</span>'
65
66
  const counts = f.binary ? '<span class="wid-n">binary</span>' : f.big ? '<span class="wid-n">big</span>' : '<span class="wid-add">+' + esc(f.add) + '</span> <span class="wid-del">−' + esc(f.del) + '</span>' + bar
66
- let h = '<li class="wid-item' + (open ? ' open' : '') + '">'
67
+ let h = '<li class="wid-item' + (open ? ' open' : '') + (f.notSession ? ' nots' : '') + '">'
67
68
  h += '<button type="button" class="wid-row wid-file" data-action="wid-file" data-id="' + esc(sid) + '" data-path="' + esc(f.path) + '" aria-expanded="' + open + '" aria-controls="' + bodyId + '">'
68
69
  h += '<span class="wid-chev" aria-hidden="true">' + icon(open ? 'chevron-down' : 'chevron-right') + '</span>'
69
70
  h += '<span class="wid-st st-' + esc(f.status) + '" data-tip="' + esc(word) + '" aria-label="' + esc(word) + '">' + letter + '</span>'
70
71
  const [dir, base] = splitPath(f.path)
71
- h += '<span class="wid-path mono">' + (dir ? '<span class="wid-dir">' + esc(dir) + '</span>' : '') + '<b class="wid-base">' + esc(base) + '</b></span><span class="wid-counts">' + counts + '</span></button>'
72
+ h += '<span class="wid-path mono">' + (dir ? '<span class="wid-dir">' + esc(dir) + '</span>' : '') + '<b class="wid-base">' + esc(base) + '</b>' + scopeTagHtml(f, { esc }) + '</span><span class="wid-counts">' + counts + '</span></button>'
72
73
  if (open) {
73
74
  const v = ui.files[f.path]
74
75
  h += '<div class="wid-out" id="' + bodyId + '">'
@@ -91,16 +92,22 @@ export function fileRowHtml(f, ui, sid) {
91
92
 
92
93
  function diffHtml(ui, sid) {
93
94
  const d = ui.diff
94
- let h = '<div class="wid-sub"><h3>This folder’s changes</h3>'
95
+ // 2026-11-03 scoped like the walkthrough: This session (the default) or Whole folder, counts on both
96
+ const fsc = d && d.fileScope && d.fileScope.session != null ? d.fileScope : null
97
+ const title = fsc && fsc.key !== 'folder' ? 'This session’s changes' : 'This folder’s changes'
98
+ let h = '<div class="wid-sub"><h3>' + title + '</h3>'
95
99
  if (d && d.folder && !d.tooBig && !d.noRepo) h += '<span class="wid-meta">' + esc(d.folder) + (d.totals && d.totals.files ? ' · ' + plural(d.totals.files, 'file') + ' · <span class="wid-add">+' + esc(d.totals.add) + '</span> <span class="wid-del">−' + esc(d.totals.del) + '</span>' : '') + '</span>'
96
100
  h += '</div>'
101
+ if (fsc) h += '<div class="wid-scope">' + fileScopeSegHtml(fsc, { esc, icon, action: 'wid-files', busy: !!ui.loading }) + '</div>'
97
102
  if (ui.diffError) return h + '<p class="wid-note">' + esc(ui.diffError) + '</p>'
98
103
  if (!d) return h + '<p class="wid-note">Loading…</p>'
99
104
  if (d.tooBig) return h + '<p class="wid-note">Too big to show here.</p>'
100
105
  if (d.noRepo) return h + '<p class="wid-note">' + (d.noRepo === 'not_a_repo' ? 'This folder isn’t a git repository.' : d.noRepo === 'no_git' ? 'git isn’t installed on that Mac.' : 'This session’s folder isn’t there any more.') + '</p>'
101
- if (!d.files || !d.files.length) return h + '<p class="wid-note">No uncommitted changes.</p>'
102
- h += '<ul class="wid-list">' + d.files.map((f) => fileRowHtml(f, ui, sid)).join('') + '</ul>'
106
+ const notes = unreadableLines({ baseNotes: d.baseNotes }).map((l) => '<p class="wid-note wid-scope-n">' + icon('info') + '<span>' + esc(l) + '</span></p>').join('')
107
+ if (!d.files || !d.files.length) return h + notes + '<p class="wid-note">' + (fsc && fsc.key !== 'folder' ? (fsc.folder ? 'No uncommitted changes from this session (' + plural(fsc.folder, 'file') + ' in the whole folder).' : 'No uncommitted changes from this session.') : 'No uncommitted changes.') + '</p>'
108
+ h += notes + '<ul class="wid-list">' + d.files.map((f) => fileRowHtml(f, ui, sid)).join('') + '</ul>'
103
109
  if (d.truncated) h += '<p class="wid-note">Showing the first ' + d.files.length + ' of ' + esc(d.totals.files) + ' files.</p>'
110
+ if (fsc && fsc.key !== 'folder') return h + '<p class="wid-foot">Uncommitted changes this session made in its folder. Whole folder shows everything, other sessions’ changes too.</p>'
104
111
  return h + '<p class="wid-foot">Uncommitted changes in the session’s folder (staged, unstaged and new files). Other sessions in this folder show the same changes.</p>'
105
112
  }
106
113