git-viewer 8.0.0 → 9.0.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.
@@ -1597,7 +1597,8 @@ var state = {
1597
1597
  diff: null,
1598
1598
  filter: "all",
1599
1599
  search: "",
1600
- loading: true
1600
+ loading: true,
1601
+ fullscreenDiff: false
1601
1602
  };
1602
1603
  var updateApp;
1603
1604
  async function fetchRefs() {
@@ -1645,6 +1646,17 @@ async function selectCommit(commit) {
1645
1646
  state.diff = await fetchDiff(commit.sha);
1646
1647
  updateApp();
1647
1648
  }
1649
+ function toggleFullscreenDiff(open) {
1650
+ if (!document.startViewTransition) {
1651
+ state.fullscreenDiff = open;
1652
+ updateApp();
1653
+ return;
1654
+ }
1655
+ document.startViewTransition(() => {
1656
+ state.fullscreenDiff = open;
1657
+ updateApp();
1658
+ });
1659
+ }
1648
1660
  var colors = {
1649
1661
  bg: "#ffffff",
1650
1662
  bgLight: "#f6f8fa",
@@ -1711,9 +1723,6 @@ function Sidebar() {
1711
1723
  "div",
1712
1724
  {
1713
1725
  css: {
1714
- minWidth: "180px",
1715
- maxWidth: "300px",
1716
- width: "fit-content",
1717
1726
  borderRight: `1px solid ${colors.border}`,
1718
1727
  display: "flex",
1719
1728
  flexDirection: "column",
@@ -1725,7 +1734,6 @@ function Sidebar() {
1725
1734
  {
1726
1735
  css: {
1727
1736
  padding: "12px",
1728
- borderBottom: `1px solid ${colors.border}`,
1729
1737
  fontWeight: 600,
1730
1738
  fontSize: "11px",
1731
1739
  textTransform: "uppercase",
@@ -1837,7 +1845,7 @@ function RefNodeItem(handle) {
1837
1845
  },
1838
1846
  on: { click: () => setFilter(node.fullName) },
1839
1847
  children: [
1840
- node.current && "\u25CF ",
1848
+ node.current && /* @__PURE__ */ jsx("span", { css: { fontSize: "8px", marginRight: "4px" }, children: "\u25CF" }),
1841
1849
  node.name
1842
1850
  ]
1843
1851
  }
@@ -2125,7 +2133,20 @@ function CommitRow() {
2125
2133
  };
2126
2134
  }
2127
2135
  function DiffPanel() {
2136
+ let diffContentRef;
2137
+ function scrollToFile(path) {
2138
+ if (!diffContentRef || !path) return;
2139
+ let fileHeaders = diffContentRef.querySelectorAll(".d2h-file-header");
2140
+ for (let header of fileHeaders) {
2141
+ let nameEl = header.querySelector(".d2h-file-name");
2142
+ if (nameEl?.textContent?.includes(path)) {
2143
+ header.scrollIntoView({ block: "start" });
2144
+ break;
2145
+ }
2146
+ }
2147
+ }
2128
2148
  return () => {
2149
+ let isFullscreen = state.fullscreenDiff;
2129
2150
  if (!state.selectedCommit) {
2130
2151
  return /* @__PURE__ */ jsx(
2131
2152
  "div",
@@ -2149,76 +2170,333 @@ function DiffPanel() {
2149
2170
  flex: 1,
2150
2171
  display: "flex",
2151
2172
  flexDirection: "column",
2152
- background: colors.bgLight
2173
+ background: colors.bgLight,
2174
+ viewTransitionName: "diff-panel",
2175
+ ...isFullscreen ? {
2176
+ position: "fixed",
2177
+ top: 0,
2178
+ left: 0,
2179
+ right: 0,
2180
+ bottom: 0,
2181
+ zIndex: 100
2182
+ } : {}
2153
2183
  },
2154
2184
  children: [
2155
2185
  /* @__PURE__ */ jsx(
2156
2186
  "div",
2157
2187
  {
2158
- css: { padding: "12px", borderBottom: `1px solid ${colors.border}` },
2188
+ css: {
2189
+ padding: "12px",
2190
+ borderBottom: `1px solid ${colors.border}`,
2191
+ display: "flex",
2192
+ alignItems: "flex-start",
2193
+ justifyContent: "space-between",
2194
+ gap: "12px",
2195
+ background: colors.bgLight
2196
+ },
2159
2197
  children: [
2160
- /* @__PURE__ */ jsx("div", { css: { fontWeight: 600, marginBottom: "4px" }, children: state.selectedCommit.subject }),
2161
- /* @__PURE__ */ jsx("div", { css: { fontSize: "12px", color: colors.textMuted }, children: [
2162
- /* @__PURE__ */ jsx("span", { children: state.selectedCommit.author }),
2163
- /* @__PURE__ */ jsx("span", { css: { margin: "0 8px" }, children: "\u2022" }),
2164
- /* @__PURE__ */ jsx("span", { children: state.selectedCommit.date }),
2165
- /* @__PURE__ */ jsx("span", { css: { margin: "0 8px" }, children: "\u2022" }),
2166
- /* @__PURE__ */ jsx("code", { css: { color: colors.accent }, children: state.selectedCommit.shortSha })
2198
+ /* @__PURE__ */ jsx("div", { css: { flex: 1, minWidth: 0 }, children: [
2199
+ /* @__PURE__ */ jsx("div", { css: { fontWeight: 600, marginBottom: "4px" }, children: state.selectedCommit.subject }),
2200
+ /* @__PURE__ */ jsx("div", { css: { fontSize: "12px", color: colors.textMuted }, children: [
2201
+ /* @__PURE__ */ jsx("span", { children: state.selectedCommit.author }),
2202
+ /* @__PURE__ */ jsx("span", { css: { margin: "0 8px" }, children: "\u2022" }),
2203
+ /* @__PURE__ */ jsx("span", { children: state.selectedCommit.date }),
2204
+ /* @__PURE__ */ jsx("span", { css: { margin: "0 8px" }, children: "\u2022" }),
2205
+ /* @__PURE__ */ jsx("code", { css: { color: colors.accent }, children: state.selectedCommit.shortSha }),
2206
+ state.diff && /* @__PURE__ */ jsx(Fragment, { children: [
2207
+ /* @__PURE__ */ jsx("span", { css: { margin: "0 8px" }, children: "\u2022" }),
2208
+ /* @__PURE__ */ jsx("span", { children: [
2209
+ state.diff.files.length,
2210
+ " file",
2211
+ state.diff.files.length !== 1 ? "s" : ""
2212
+ ] })
2213
+ ] })
2214
+ ] }),
2215
+ state.selectedCommit.body && /* @__PURE__ */ jsx(
2216
+ "div",
2217
+ {
2218
+ css: {
2219
+ marginTop: "8px",
2220
+ whiteSpace: "pre-wrap",
2221
+ fontSize: "12px",
2222
+ lineHeight: "1.4"
2223
+ },
2224
+ children: state.selectedCommit.body
2225
+ }
2226
+ )
2167
2227
  ] }),
2168
- state.selectedCommit.body ? /* @__PURE__ */ jsx(
2169
- "div",
2228
+ state.diff && /* @__PURE__ */ jsx(
2229
+ "button",
2170
2230
  {
2171
2231
  css: {
2172
- marginTop: "8px",
2173
- whiteSpace: "pre-wrap",
2232
+ display: "flex",
2233
+ alignItems: "center",
2234
+ gap: "6px",
2235
+ padding: "6px 12px",
2236
+ border: `1px solid ${colors.border}`,
2237
+ borderRadius: "4px",
2238
+ background: colors.bg,
2239
+ color: colors.text,
2174
2240
  fontSize: "12px",
2175
- lineHeight: "1.4"
2241
+ cursor: "pointer",
2242
+ whiteSpace: "nowrap",
2243
+ "&:hover": {
2244
+ background: colors.bgLighter,
2245
+ borderColor: colors.accent
2246
+ }
2176
2247
  },
2177
- children: state.selectedCommit.body
2248
+ on: { click: () => toggleFullscreenDiff(!isFullscreen) },
2249
+ children: isFullscreen ? /* @__PURE__ */ jsx(Fragment, { children: [
2250
+ /* @__PURE__ */ jsx(
2251
+ "svg",
2252
+ {
2253
+ width: "14",
2254
+ height: "14",
2255
+ viewBox: "0 0 24 24",
2256
+ fill: "none",
2257
+ stroke: "currentColor",
2258
+ "stroke-width": "2",
2259
+ children: /* @__PURE__ */ jsx("path", { d: "M4 14h6v6m10-10h-6V4m0 6 7-7M3 21l7-7" })
2260
+ }
2261
+ ),
2262
+ "Collapse"
2263
+ ] }) : /* @__PURE__ */ jsx(Fragment, { children: [
2264
+ /* @__PURE__ */ jsx(
2265
+ "svg",
2266
+ {
2267
+ width: "14",
2268
+ height: "14",
2269
+ viewBox: "0 0 24 24",
2270
+ fill: "none",
2271
+ stroke: "currentColor",
2272
+ "stroke-width": "2",
2273
+ children: /* @__PURE__ */ jsx("path", { d: "M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" })
2274
+ }
2275
+ ),
2276
+ "Expand"
2277
+ ] })
2178
2278
  }
2179
- ) : null
2279
+ )
2180
2280
  ]
2181
2281
  }
2182
2282
  ),
2183
- /* @__PURE__ */ jsx("div", { css: { flex: 1, overflow: "auto" }, children: state.diff ? /* @__PURE__ */ jsx(
2184
- "section",
2185
- {
2186
- css: {
2187
- "& .d2h-wrapper": { background: "transparent" },
2188
- "& .d2h-file-header": {
2189
- background: colors.bgLighter,
2190
- borderBottom: `1px solid ${colors.border}`,
2191
- padding: "8px 12px"
2283
+ /* @__PURE__ */ jsx("div", { css: { flex: 1, display: "flex", overflow: "hidden" }, children: [
2284
+ state.diff && state.diff.files.length > 0 && /* @__PURE__ */ jsx(
2285
+ "div",
2286
+ {
2287
+ css: {
2288
+ borderRight: `1px solid ${colors.border}`,
2289
+ display: "flex",
2290
+ flexDirection: "column",
2291
+ background: colors.bg,
2292
+ overflow: "hidden"
2192
2293
  },
2193
- "& .d2h-file-name": { color: colors.text },
2194
- "& .d2h-code-line": { padding: "0 8px" },
2195
- "& .d2h-code-line-ctn": { color: colors.text },
2196
- "& .d2h-ins": { background: "#dafbe1" },
2197
- "& .d2h-del": { background: "#ffebe9" },
2198
- "& .d2h-ins .d2h-code-line-ctn": { color: colors.green },
2199
- "& .d2h-del .d2h-code-line-ctn": { color: colors.red },
2200
- "& .d2h-code-linenumber": {
2201
- color: colors.textMuted,
2202
- borderRight: `1px solid ${colors.border}`
2294
+ children: [
2295
+ /* @__PURE__ */ jsx(
2296
+ "div",
2297
+ {
2298
+ css: {
2299
+ padding: "8px 12px",
2300
+ fontSize: "11px",
2301
+ fontWeight: 600,
2302
+ textTransform: "uppercase",
2303
+ letterSpacing: "0.5px",
2304
+ color: colors.textMuted,
2305
+ borderBottom: `1px solid ${colors.border}`
2306
+ },
2307
+ children: "Changed Files"
2308
+ }
2309
+ ),
2310
+ /* @__PURE__ */ jsx("div", { css: { flex: 1, overflow: "auto", padding: "4px 0" }, children: state.diff.files.map((file) => /* @__PURE__ */ jsx(
2311
+ FileListItem,
2312
+ {
2313
+ file,
2314
+ onSelect: () => scrollToFile(file.path)
2315
+ },
2316
+ file.path
2317
+ )) })
2318
+ ]
2319
+ }
2320
+ ),
2321
+ /* @__PURE__ */ jsx("div", { css: { flex: 1, overflow: "auto" }, children: state.diff ? /* @__PURE__ */ jsx(
2322
+ "section",
2323
+ {
2324
+ connect: (node) => diffContentRef = node,
2325
+ css: {
2326
+ "& .d2h-wrapper": { background: "transparent" },
2327
+ "& .d2h-file-header": {
2328
+ background: colors.bgLighter,
2329
+ borderBottom: `1px solid ${colors.border}`,
2330
+ padding: "8px 12px",
2331
+ position: "sticky",
2332
+ top: 0,
2333
+ zIndex: 1
2334
+ },
2335
+ "& .d2h-file-name": { color: colors.text },
2336
+ "& .d2h-code-line": { padding: "0 8px" },
2337
+ "& .d2h-code-line-ctn": { color: colors.text },
2338
+ "& .d2h-ins": { background: "#dafbe1" },
2339
+ "& .d2h-del": { background: "#ffebe9" },
2340
+ "& .d2h-ins .d2h-code-line-ctn": { color: colors.green },
2341
+ "& .d2h-del .d2h-code-line-ctn": { color: colors.red },
2342
+ "& .d2h-code-linenumber": {
2343
+ color: colors.textMuted,
2344
+ borderRight: `1px solid ${colors.border}`
2345
+ },
2346
+ "& .d2h-file-diff": {
2347
+ borderBottom: `1px solid ${colors.border}`
2348
+ },
2349
+ "& .d2h-diff-tbody": { position: "relative" }
2203
2350
  },
2204
- "& .d2h-file-diff": {
2205
- borderBottom: `1px solid ${colors.border}`
2351
+ innerHTML: state.diff.diffHtml
2352
+ }
2353
+ ) : /* @__PURE__ */ jsx(
2354
+ "div",
2355
+ {
2356
+ css: {
2357
+ padding: "20px",
2358
+ textAlign: "center",
2359
+ color: colors.textMuted
2206
2360
  },
2207
- "& .d2h-diff-tbody": { position: "relative" }
2361
+ children: "Loading diff..."
2362
+ }
2363
+ ) })
2364
+ ] })
2365
+ ]
2366
+ }
2367
+ );
2368
+ };
2369
+ }
2370
+ function FileListItem() {
2371
+ return ({ file, onSelect }) => {
2372
+ let displayName = file.path.split("/").pop() ?? file.path;
2373
+ let fullPath = file.path;
2374
+ return /* @__PURE__ */ jsx(
2375
+ "div",
2376
+ {
2377
+ css: {
2378
+ padding: "6px 12px",
2379
+ cursor: "pointer",
2380
+ "&:hover": {
2381
+ background: colors.bgLighter
2382
+ }
2383
+ },
2384
+ on: { click: onSelect },
2385
+ children: [
2386
+ /* @__PURE__ */ jsx(
2387
+ "div",
2388
+ {
2389
+ css: {
2390
+ display: "flex",
2391
+ alignItems: "center",
2392
+ gap: "8px"
2208
2393
  },
2209
- innerHTML: state.diff.diffHtml
2394
+ children: [
2395
+ /* @__PURE__ */ jsx(
2396
+ "span",
2397
+ {
2398
+ css: {
2399
+ display: "flex",
2400
+ alignItems: "center",
2401
+ gap: "2px",
2402
+ fontSize: "10px",
2403
+ fontWeight: 500,
2404
+ minWidth: "50px"
2405
+ },
2406
+ children: [
2407
+ file.additions > 0 && /* @__PURE__ */ jsx("span", { css: { color: colors.green }, children: [
2408
+ "+",
2409
+ file.additions
2410
+ ] }),
2411
+ file.deletions > 0 && /* @__PURE__ */ jsx("span", { css: { color: colors.red }, children: [
2412
+ "-",
2413
+ file.deletions
2414
+ ] })
2415
+ ]
2416
+ }
2417
+ ),
2418
+ /* @__PURE__ */ jsx(
2419
+ "span",
2420
+ {
2421
+ css: {
2422
+ flex: 1,
2423
+ overflow: "hidden",
2424
+ textOverflow: "ellipsis",
2425
+ whiteSpace: "nowrap",
2426
+ fontSize: "12px"
2427
+ },
2428
+ title: fullPath,
2429
+ children: [
2430
+ file.isNew && /* @__PURE__ */ jsx(
2431
+ "span",
2432
+ {
2433
+ css: {
2434
+ display: "inline-block",
2435
+ padding: "1px 4px",
2436
+ marginRight: "6px",
2437
+ borderRadius: "3px",
2438
+ background: colors.green,
2439
+ color: "#fff",
2440
+ fontSize: "9px",
2441
+ fontWeight: 600
2442
+ },
2443
+ children: "NEW"
2444
+ }
2445
+ ),
2446
+ file.isDeleted && /* @__PURE__ */ jsx(
2447
+ "span",
2448
+ {
2449
+ css: {
2450
+ display: "inline-block",
2451
+ padding: "1px 4px",
2452
+ marginRight: "6px",
2453
+ borderRadius: "3px",
2454
+ background: colors.red,
2455
+ color: "#fff",
2456
+ fontSize: "9px",
2457
+ fontWeight: 600
2458
+ },
2459
+ children: "DEL"
2460
+ }
2461
+ ),
2462
+ file.isRenamed && /* @__PURE__ */ jsx(
2463
+ "span",
2464
+ {
2465
+ css: {
2466
+ display: "inline-block",
2467
+ padding: "1px 4px",
2468
+ marginRight: "6px",
2469
+ borderRadius: "3px",
2470
+ background: colors.accent,
2471
+ color: "#fff",
2472
+ fontSize: "9px",
2473
+ fontWeight: 600
2474
+ },
2475
+ children: "REN"
2476
+ }
2477
+ ),
2478
+ displayName
2479
+ ]
2480
+ }
2481
+ )
2482
+ ]
2210
2483
  }
2211
- ) : /* @__PURE__ */ jsx(
2484
+ ),
2485
+ fullPath !== displayName && /* @__PURE__ */ jsx(
2212
2486
  "div",
2213
2487
  {
2214
2488
  css: {
2215
- padding: "20px",
2216
- textAlign: "center",
2217
- color: colors.textMuted
2489
+ fontSize: "10px",
2490
+ color: colors.textMuted,
2491
+ marginTop: "2px",
2492
+ marginLeft: "58px",
2493
+ overflow: "hidden",
2494
+ textOverflow: "ellipsis",
2495
+ whiteSpace: "nowrap"
2218
2496
  },
2219
- children: "Loading diff..."
2497
+ children: fullPath
2220
2498
  }
2221
- ) })
2499
+ )
2222
2500
  ]
2223
2501
  }
2224
2502
  );
package/dist/index.html CHANGED
@@ -13,6 +13,38 @@
13
13
  height: 100%;
14
14
  overflow: hidden;
15
15
  }
16
+
17
+ /* View Transition Styles */
18
+ @view-transition {
19
+ navigation: auto;
20
+ }
21
+
22
+ /* Diff panel morphs between positions */
23
+ ::view-transition-old(diff-panel),
24
+ ::view-transition-new(diff-panel) {
25
+ animation-duration: 0.35s;
26
+ animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
27
+ }
28
+
29
+ /* Make the old and new states crossfade while morphing */
30
+ ::view-transition-old(diff-panel) {
31
+ animation: none;
32
+ }
33
+
34
+ ::view-transition-new(diff-panel) {
35
+ animation: none;
36
+ }
37
+
38
+ /* The group handles the position/size morphing automatically */
39
+ ::view-transition-group(diff-panel) {
40
+ animation-duration: 0.35s;
41
+ animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
42
+ }
43
+
44
+ /* Image pair handles crossfade */
45
+ ::view-transition-image-pair(diff-panel) {
46
+ isolation: auto;
47
+ }
16
48
  </style>
17
49
  </head>
18
50
  <body>
package/dist/server.js CHANGED
@@ -8854,11 +8854,11 @@ async function getRefs() {
8854
8854
  }
8855
8855
  let remotes = {};
8856
8856
  for (let [remote, branches] of Object.entries(remotesByOrigin)) {
8857
- remotes[remote] = buildTree(branches);
8857
+ remotes[remote] = buildTree(branches, void 0, `${remote}/`);
8858
8858
  }
8859
8859
  return { local, remotes, currentBranch };
8860
8860
  }
8861
- function buildTree(branches, currentBranch) {
8861
+ function buildTree(branches, currentBranch, prefix = "") {
8862
8862
  let root = [];
8863
8863
  let sorted = [...branches].sort((a, b) => {
8864
8864
  let aHasSlash = a.includes("/");
@@ -8868,7 +8868,7 @@ function buildTree(branches, currentBranch) {
8868
8868
  });
8869
8869
  for (let branch of sorted) {
8870
8870
  let parts = branch.split("/");
8871
- insertIntoTree(root, parts, branch, currentBranch);
8871
+ insertIntoTree(root, parts, prefix + branch, currentBranch);
8872
8872
  }
8873
8873
  return root;
8874
8874
  }
@@ -9039,7 +9039,17 @@ async function getDiff(sha) {
9039
9039
  let [record] = metaOutput.split("\0");
9040
9040
  let [fullSha, shortSha, subject, body, author, date, parents] = record.split("");
9041
9041
  let diffOutput = await git(`show --format="" ${sha}`);
9042
- let diffHtml = (0, import_diff2html.html)((0, import_diff2html.parse)(diffOutput), {
9042
+ let parsedDiff = (0, import_diff2html.parse)(diffOutput);
9043
+ let files = parsedDiff.map((file) => ({
9044
+ path: file.newName || file.oldName || "",
9045
+ oldPath: file.isRename ? file.oldName : void 0,
9046
+ additions: file.addedLines,
9047
+ deletions: file.deletedLines,
9048
+ isNew: file.isNew || false,
9049
+ isDeleted: file.isDeleted || false,
9050
+ isRenamed: file.isRename || false
9051
+ }));
9052
+ let diffHtml = (0, import_diff2html.html)(parsedDiff, {
9043
9053
  drawFileList: false,
9044
9054
  outputFormat: "line-by-line",
9045
9055
  matching: "lines"
@@ -9052,7 +9062,8 @@ async function getDiff(sha) {
9052
9062
  author,
9053
9063
  date: formatDate(date),
9054
9064
  parents: parents ? parents.split(" ").filter(Boolean) : [],
9055
- diffHtml
9065
+ diffHtml,
9066
+ files
9056
9067
  };
9057
9068
  }
9058
9069
  var packageDir = import.meta.dirname;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-viewer",
3
- "version": "8.0.0",
3
+ "version": "9.0.0",
4
4
  "description": "Visual git log viewer with branch graph and diff display",
5
5
  "repository": {
6
6
  "type": "git",