dsh-ui-tweaks 0.7.0 → 0.7.2

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/lib/client.js CHANGED
@@ -328,36 +328,59 @@ exports.GITBAR_CSS = `
328
328
  .gbar-pill .gbar-caret{display:none}
329
329
  }
330
330
 
331
- /* branch popup — opens upward so the composer below stays uncovered */
331
+ /* branch popup — opens upward so the composer below stays uncovered. Pinned
332
+ header (current branch + worktree state) and pinned action bar surround a
333
+ freely scrolling branch list. */
332
334
  .gbar-pop{
333
335
  position:absolute;left:0;bottom:calc(100% + 6px);z-index:90;
334
- width:286px;max-height:min(360px,calc(100vh - 140px));overflow:hidden auto;
336
+ width:300px;
335
337
  background:var(--dsw-alias-bg-layer-1);
336
338
  border:1px solid var(--dsw-alias-border-l2);border-radius:14px;
337
339
  box-shadow:var(--dsw-shadow-lv2);
338
- padding:6px;display:flex;flex-direction:column;gap:1px;
340
+ display:flex;flex-direction:column;overflow:hidden;
339
341
  }
340
- .gbar-pop .gbar-sec{font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);padding:7px 9px 3px}
342
+ .gbar-pop-head{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform)}
343
+ .gbar-pop-head .gbar-bicon{width:14px;height:14px;flex:none}
344
+ .gbar-pop-head .gbar-curname{display:flex;align-items:center;gap:7px;min-width:0;font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary)}
345
+ .gbar-pop-head .gbar-curname .gbar-bicon{color:var(--dsw-alias-state-business-primary)}
346
+ .gbar-pop-head .gbar-curname>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
347
+ .gbar-pop-head .gbar-state{margin-left:auto;flex:none;display:flex;align-items:center;gap:6px;font-size:11px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums}
348
+ .gbar-pop-head .gbar-dot{width:6px;height:6px;border-radius:50%;flex:none}
349
+ .gbar-pop-head .gbar-dot.gbar-dirty{background:var(--dsw-alias-state-warn-primary)}
350
+ .gbar-pop-head .gbar-dot.gbar-clean{background:var(--dsw-alias-state-success-primary)}
351
+ .gbar-pop-body{max-height:min(330px,calc(100vh - 250px));overflow-y:auto;padding:3px 6px 5px;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent) transparent}
352
+ .gbar-pop-body::-webkit-scrollbar{width:5px}
353
+ .gbar-pop-body::-webkit-scrollbar-track{background:transparent}
354
+ .gbar-pop-body::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent);border-radius:4px}
355
+ .gbar-pop .gbar-sec{display:flex;align-items:center;gap:6px;font-size:10.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);padding:8px 9px 3px}
356
+ .gbar-pop .gbar-sec .gbar-count{margin-left:auto;font-size:10px;font-weight:500;letter-spacing:0;line-height:15px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform);border-radius:999px;padding:0 7px}
357
+ .gbar-pop .gbar-loading{display:flex;align-items:center;justify-content:center;gap:8px;padding:14px 9px;font-size:12px;color:var(--dsw-alias-label-tertiary)}
341
358
  .gbar-pop .gbar-row{
342
359
  display:flex;align-items:center;gap:8px;width:100%;
343
- padding:7px 9px;border:none;border-radius:8px;
360
+ padding:6px 8px;border:none;border-radius:8px;
344
361
  background:transparent;color:var(--dsw-alias-label-primary);
345
- font:inherit;font-size:13px;cursor:pointer;text-align:left;
362
+ font:inherit;font-size:12.5px;cursor:pointer;text-align:left;
363
+ transition:background .12s ease;
346
364
  }
347
365
  .gbar-pop .gbar-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
348
366
  .gbar-pop .gbar-row.gbar-cur{color:var(--dsw-alias-state-business-primary);font-weight:600}
367
+ .gbar-pop .gbar-row .gbar-bicon{width:13px;height:13px;flex:none;color:var(--dsw-alias-label-tertiary);opacity:.85}
368
+ .gbar-pop .gbar-row.gbar-cur .gbar-bicon{color:var(--dsw-alias-state-business-primary);opacity:1}
349
369
  .gbar-pop .gbar-row .gbar-check{margin-left:auto;color:var(--dsw-alias-state-business-primary);font-weight:700}
350
- .gbar-pop .gbar-row .gbar-rm{font-size:10.5px;color:var(--dsw-alias-label-tertiary);flex:none}
370
+ .gbar-pop .gbar-row .gbar-rm{flex:none;font-size:10px;line-height:15px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform);border-radius:999px;padding:0 7px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:90px}
351
371
  /* branch row wrapper: main switch button + delete button */
352
- .gbar-pop .gbar-rowwrap{display:flex;align-items:center;gap:2px;border-radius:8px}
372
+ .gbar-pop .gbar-rowwrap{display:flex;align-items:center;gap:2px;border-radius:8px;transition:background .12s ease}
353
373
  .gbar-pop .gbar-rowwrap:hover{background:var(--dsw-alias-interactive-bg-hover)}
354
374
  .gbar-pop .gbar-rowwrap .gbar-row{background:transparent}
355
375
  .gbar-pop .gbar-del{
356
- flex:none;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);
357
- font:inherit;font-size:12px;cursor:pointer;padding:6px 8px;border-radius:6px;margin-right:3px;
376
+ flex:none;display:inline-flex;align-items:center;justify-content:center;
377
+ width:26px;height:26px;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);
378
+ font:inherit;font-size:10.5px;cursor:pointer;border-radius:7px;margin-right:4px;
379
+ transition:color .12s ease,background .12s ease;
358
380
  }
381
+ .gbar-pop .gbar-del svg{width:13px;height:13px;display:block}
359
382
  .gbar-pop .gbar-del:hover{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
360
- .gbar-pop .gbar-del.gbar-arm{color:var(--dsw-alias-state-error-primary);font-weight:600}
383
+ .gbar-pop .gbar-del.gbar-arm{width:auto;padding:0 8px;color:var(--dsw-alias-state-error-primary);font-weight:600;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
361
384
  .gbar-pushrow{display:flex;align-items:center;gap:7px;padding:0 8px 7px}
362
385
  .gbar-pushrow .gbar-pushlabel{font-size:12px;color:var(--dsw-alias-label-secondary)}
363
386
  .gbar-pop .gbar-newrow{display:flex;gap:6px;padding:8px 6px 6px}
@@ -377,8 +400,9 @@ exports.GITBAR_CSS = `
377
400
  .gbar-mini:hover{opacity:.92}
378
401
  .gbar-mini:disabled{opacity:.5;cursor:default}
379
402
 
380
- /* branch popup action entries (new branch / graph) */
381
- .gbar-actions{display:flex;gap:6px;padding:8px 6px 4px;border-top:1px solid var(--dsw-alias-border-l1);margin-top:4px}
403
+ /* branch popup action entries (new branch / graph) — pinned below the
404
+ scrolling list; the border-top separates it from the body. */
405
+ .gbar-actions{display:flex;gap:6px;padding:8px;border-top:1px solid var(--dsw-alias-border-l1)}
382
406
  .gbar-act{
383
407
  flex:1;display:inline-flex;align-items:center;justify-content:center;gap:7px;
384
408
  height:34px;border:none;border-radius:10px;
@@ -405,7 +429,10 @@ exports.GITBAR_CSS = `
405
429
  }
406
430
  .gbar-modal input:focus{border-color:var(--dsw-alias-state-business-primary)}
407
431
  .gbar-modal input::placeholder{color:var(--dsw-alias-label-tertiary)}
408
- .gbar-modal .gbar-pushrow{padding:0}
432
+ .gbar-modal .gbar-head{padding-bottom:10px;border-bottom:1px solid var(--dsw-alias-border-l1)}
433
+ /* "push to remote" row becomes an inset card so it reads as one option group. */
434
+ .gbar-modal .gbar-pushrow{padding:9px 11px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-2)}
435
+ .gbar-modal .gbar-pushrow .gbar-pushlabel{font-size:12.5px;color:var(--dsw-alias-label-primary)}
409
436
  .gbar-x:disabled{opacity:.5;cursor:default}
410
437
  /* commit-graph dialog */
411
438
  .gbar-modal.gbar-graph-modal{width:min(760px,calc(100vw - 40px));gap:10px}
@@ -417,12 +444,14 @@ exports.GITBAR_CSS = `
417
444
  .gbar-modal.gbar-graph-modal .gbar-x svg{width:15px;height:15px;display:block}
418
445
  .gbar-graph-empty{padding:28px 12px;text-align:center;font-size:13px;color:var(--dsw-alias-label-tertiary)}
419
446
  .gbar-graph-table{display:flex;flex-direction:column;max-height:min(60vh,540px);overflow:auto;border:1px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-bg-layer-2)}
420
- .gbar-graph-row{display:grid;grid-template-columns:62px 1fr 96px 90px;align-items:center;gap:8px;padding:5px 12px;border-bottom:1px solid var(--dsw-alias-border-l1)}
447
+ .gbar-graph-row{display:grid;grid-template-columns:62px 1fr 96px 90px;align-items:center;gap:8px;padding:5px 12px;border-bottom:1px solid var(--dsw-alias-border-l1);transition:background .12s ease}
421
448
  .gbar-graph-row:last-child{border-bottom:none}
422
- .gbar-graph-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
423
- .gbar-graph-head{position:sticky;top:0;background:var(--dsw-alias-bg-module-platform);font-size:10.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);z-index:1}
424
- .gbar-graph-head:hover{background:var(--dsw-alias-bg-module-platform)}
425
- .gbar-c-hash code{font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:11px;color:var(--dsw-alias-label-secondary)}
449
+ /* Zebra striping for scanability; the hover rule matches its specificity and
450
+ comes later in the sheet, so pointing at a row still wins. */
451
+ .gbar-graph-row:not(.gbar-graph-head):nth-child(odd){background:color-mix(in srgb,var(--dsw-alias-bg-module-platform) 35%,transparent)}
452
+ .gbar-graph-row:not(.gbar-graph-head):hover{background:var(--dsw-alias-interactive-bg-hover)}
453
+ .gbar-graph-head{position:sticky;top:0;background:var(--dsw-alias-bg-module-platform);font-size:10.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);z-index:1;border-bottom:1px solid var(--dsw-alias-border-l1)}
454
+ .gbar-c-hash code{font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-module-platform);border-radius:6px;padding:2px 6px}
426
455
  .gbar-c-subject{min-width:0;display:flex;align-items:center;gap:8px}
427
456
  .gbar-subject{font-size:12.5px;color:var(--dsw-alias-label-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
428
457
  .gbar-refs{flex:none;font-size:10.5px;color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);border-radius:999px;padding:1px 8px;white-space:nowrap;max-width:220px;overflow:hidden;text-overflow:ellipsis}
@@ -453,7 +482,9 @@ exports.GITBAR_CSS = `
453
482
  @keyframes gbar-in{from{opacity:0;transform:translateX(14px)}to{opacity:1;transform:none}}
454
483
  .gbar-side-head{display:flex;align-items:center;gap:10px;padding:12px 14px;border-bottom:1px solid var(--dsw-alias-border-l1)}
455
484
  .gbar-side-head .gbar-title{font-size:13.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
456
- .gbar-side-head .gbar-sub{font-size:12px;color:var(--dsw-alias-label-tertiary);flex:none}
485
+ .gbar-side-head .gbar-sub{font-size:12px;color:var(--dsw-alias-label-tertiary);flex:none;font-variant-numeric:tabular-nums}
486
+ .gbar-side-head .gbar-sub .gbar-a{color:var(--dsw-alias-state-success-primary)}
487
+ .gbar-side-head .gbar-sub .gbar-d{color:var(--dsw-alias-state-error-primary)}
457
488
  .gbar-side-head .gbar-spacer{flex:1}
458
489
  .gbar-seg{display:inline-flex;padding:3px;gap:2px;border-radius:10px;background:var(--dsw-alias-bg-module-platform);flex:none}
459
490
  .gbar-seg button{border:none;border-radius:8px;padding:4px 10px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer}
@@ -465,7 +496,9 @@ exports.GITBAR_CSS = `
465
496
  neighbours carry an explicit inline height and the diff pane absorbs whatever
466
497
  is left, so a drag can never overflow the panel. The dividing hairlines are
467
498
  painted by the splitters, not by the sections' own borders. */
468
- .gbar-files{flex:none;overflow-y:auto}
499
+ .gbar-files{flex:none;overflow-y:auto;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent) transparent}
500
+ .gbar-files::-webkit-scrollbar{width:5px}
501
+ .gbar-files::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent);border-radius:4px}
469
502
  /* horizontal drag splitters between the sections */
470
503
  .gbar-vsplit{
471
504
  flex:none;position:relative;height:7px;
@@ -487,7 +520,7 @@ exports.GITBAR_CSS = `
487
520
  color:var(--dsw-alias-label-primary);font:inherit;font-size:12.5px;cursor:pointer;text-align:left;
488
521
  }
489
522
  .gbar-file .gbar-file-main:hover{background:var(--dsw-alias-interactive-bg-hover)}
490
- .gbar-file.gbar-on .gbar-file-main{background:var(--dsw-alias-interactive-bg-hover)}
523
+ .gbar-file.gbar-on .gbar-file-main{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 9%,transparent);box-shadow:inset 2px 0 0 var(--dsw-alias-state-business-primary)}
491
524
  .gbar-file.gbar-excl{opacity:.55}
492
525
  .gbar-chk{
493
526
  flex:none;width:16px;height:16px;padding:0;
@@ -497,26 +530,43 @@ exports.GITBAR_CSS = `
497
530
  }
498
531
  .gbar-chk:hover{border-color:var(--dsw-alias-state-business-primary)}
499
532
  .gbar-chk.gbar-off{color:transparent}
500
- .gbar-file .gbar-st{flex:none;width:16px;font-weight:700;font-size:12px}
501
- .gbar-file .gbar-st.gbar-m{color:var(--dsw-alias-state-warn-primary)}
502
- .gbar-file .gbar-st.gbar-a{color:var(--dsw-alias-state-success-primary)}
503
- .gbar-file .gbar-st.gbar-d{color:var(--dsw-alias-state-error-primary)}
504
- .gbar-file .gbar-st.gbar-u{color:var(--dsw-alias-label-tertiary)}
533
+ .gbar-file .gbar-st{
534
+ flex:none;min-width:17px;height:17px;padding:0 4px;
535
+ display:inline-flex;align-items:center;justify-content:center;
536
+ font-weight:700;font-size:10.5px;border-radius:5px;
537
+ }
538
+ .gbar-file .gbar-st.gbar-m{color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 13%,transparent)}
539
+ .gbar-file .gbar-st.gbar-a{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 13%,transparent)}
540
+ .gbar-file .gbar-st.gbar-d{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 12%,transparent)}
541
+ .gbar-file .gbar-st.gbar-u{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform)}
505
542
  .gbar-file .gbar-path{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:12px}
543
+ /* Directory part dims, filename stays bright — GitHub-style path rendering. */
544
+ .gbar-file .gbar-path .gbar-dir{color:var(--dsw-alias-label-tertiary)}
506
545
  .gbar-file .gbar-nums{flex:none;font-variant-numeric:tabular-nums;font-size:11.5px}
507
546
  .gbar-file .gbar-nums .gbar-a{color:var(--dsw-alias-state-success-primary)}
508
547
  .gbar-file .gbar-nums .gbar-d{color:var(--dsw-alias-state-error-primary)}
509
- .gbar-diff{flex:1;min-height:0;overflow:auto;font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:12px;line-height:1.7;padding:8px 0}
510
- .gbar-diff .gbar-hunk{display:flex;align-items:center;height:24px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-markdown-inline-code);padding:0 14px;font-size:11.5px;white-space:nowrap}
548
+ .gbar-diff{
549
+ flex:1;min-height:0;overflow:auto;
550
+ font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:12px;line-height:1.7;padding:8px 0;
551
+ scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent) transparent;
552
+ }
553
+ .gbar-diff::-webkit-scrollbar{width:5px;height:5px}
554
+ .gbar-diff::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent);border-radius:4px}
555
+ /* Hunk header: a centered pill strip (GitHub-style), gutter numbers hidden but
556
+ still occupying space so the code column stays aligned. */
557
+ .gbar-diff .gbar-line.gbar-hunk{background:transparent;padding-top:7px;padding-bottom:3px}
558
+ .gbar-diff .gbar-line.gbar-hunk .gbar-ln{visibility:hidden}
559
+ .gbar-diff .gbar-line.gbar-hunk .gbar-code{color:var(--dsw-alias-state-business-primary)}
511
560
  .gbar-diff .gbar-line{display:flex;align-items:center;min-height:21px;padding:0 14px 0 0;white-space:pre}
512
- .gbar-diff .gbar-line .gbar-ln{flex:none;width:46px;text-align:right;padding-right:12px;color:var(--dsw-alias-label-tertiary);font-size:11px;-webkit-user-select:none;user-select:none}
513
- .gbar-diff .gbar-line .gbar-code{flex:1;white-space:pre;color:var(--dsw-alias-label-primary)}
514
- .gbar-diff .gbar-line.gbar-add{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 14%,transparent)}
561
+ .gbar-diff .gbar-line .gbar-ln{flex:none;width:34px;text-align:right;padding-right:8px;color:var(--dsw-alias-label-tertiary);font-size:11px;-webkit-user-select:none;user-select:none}
562
+ .gbar-diff .gbar-line .gbar-ln+.gbar-ln{border-right:1px solid var(--dsw-alias-border-l1);margin-right:10px}
563
+ .gbar-diff .gbar-line .gbar-code{flex:1;white-space:pre;color:var(--dsw-alias-label-primary);padding-right:14px}
564
+ .gbar-diff .gbar-line.gbar-add{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 13%,transparent);box-shadow:inset 2px 0 0 color-mix(in srgb,var(--dsw-alias-state-success-primary) 55%,transparent)}
515
565
  .gbar-diff .gbar-line.gbar-add .gbar-ln{color:var(--dsw-alias-state-success-primary)}
516
- .gbar-diff .gbar-line.gbar-del{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
566
+ .gbar-diff .gbar-line.gbar-del{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);box-shadow:inset 2px 0 0 color-mix(in srgb,var(--dsw-alias-state-error-primary) 50%,transparent)}
517
567
  .gbar-diff .gbar-line.gbar-del .gbar-ln{color:var(--dsw-alias-state-error-primary)}
518
568
  .gbar-diff .gbar-line.gbar-ctx .gbar-code{color:var(--dsw-alias-label-secondary)}
519
- .gbar-diff .gbar-empty{padding:18px 16px;font-size:12px;color:var(--dsw-alias-label-tertiary)}
569
+ .gbar-diff .gbar-empty{display:flex;align-items:center;justify-content:center;min-height:140px;font-size:12px;color:var(--dsw-alias-label-tertiary)}
520
570
  /* The hairline above the foot is drawn by the commit splitter that precedes it. */
521
571
  .gbar-side-foot{flex:none;padding:8px 14px;font-size:11.5px;color:var(--dsw-alias-label-tertiary);display:flex;gap:8px;align-items:center}
522
572
  .gbar-side-foot .gbar-dot{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-state-warn-primary);flex:none}
@@ -876,7 +926,7 @@ function GitBarBranch({ session, controller, t }) {
876
926
  if (snapshot === null || !snapshot.isRepo)
877
927
  return null;
878
928
  const dirty = !snapshot.clean;
879
- return ((0, jsx_runtime_1.jsxs)("span", { className: "gbar", "data-slot-plugin": "dsh-ui-tweaks-gitbar", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", ref: branchRef, className: 'gbar-pill' + (branchOpen ? ' gbar-active' : ''), onClick: toggleBranch, title: dirty ? t('dirty') : t('clean'), "aria-expanded": branchOpen, children: [(0, jsx_runtime_1.jsxs)("svg", { className: "gbar-ico", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "3.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "12.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "5.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.5 5.3v5.4" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 7.3c0 3-3.5 4.8-7.5 3.4" })] }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-text gbar-branch", children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-caret", "aria-hidden": true, children: "\u25BE" })] }), branchOpen ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop", role: "menu", "aria-label": snapshot.branch ?? 'git', ref: branchPopRef, children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-sec", children: t('branchLocal') }), branches?.local.map(name => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-rowwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsx)("span", { children: name }), name === branches.current ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-check", "aria-hidden": true, children: "\u2713" }) : null] }), name !== branches.current && !isProtectedBranch(name) ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-del' + (confirmDelete === name ? ' gbar-arm' : ''), onClick: () => { deleteBranch(name); }, title: t('branchDelete'), children: confirmDelete === name ? t('branchDeleteConfirm') : '🗑' })) : null] }, name))), (0, jsx_runtime_1.jsx)("div", { className: "gbar-sec", children: t('branchRemote') }), branches?.remote.map(name => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-rowwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsx)("span", { children: shortBranch(name) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-rm", children: name.split('/')[0] })] }), !isProtectedBranch(shortBranch(name)) ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-del' + (confirmDelete === name ? ' gbar-arm' : ''), onClick: () => { deleteRemoteBranch(name); }, title: t('branchRemoteDelete'), children: confirmDelete === name ? t('branchDeleteConfirm') : '🗑' })) : null] }, name))), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-act", onClick: openNewBranch, children: [(0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M7.4 2.6a1.2 1.2 0 1 1 2.2 0l3.2 1.6a1.2 1.2 0 1 1-1.1 2.1l-2.3-1.2a2.6 2.6 0 0 1-1.1.8l.6 4.2a1.2 1.2 0 1 1-1.7.2l-.6-4.2a2.6 2.6 0 0 1-1.2-.7l-2.9 1.5a1.2 1.2 0 1 1-1.1-2.1l2.9-1.5a2.6 2.6 0 0 1 .2-1.5l-3.2-1.6a1.2 1.2 0 1 1 1.1-2.1z" }) }), t('branchNew')] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-act", onClick: openGraph, children: [(0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M3 1.5v3.4a4.4 4.4 0 0 0 4.4 4.4h5.1" }), (0, jsx_runtime_1.jsx)("path", { d: "M13 1.5v4.9a3.2 3.2 0 0 1-3.2 3.2H3" }), (0, jsx_runtime_1.jsx)("circle", { cx: "3", cy: "1.5", r: "1.2", fill: "currentColor", stroke: "none" }), (0, jsx_runtime_1.jsx)("circle", { cx: "13", cy: "12", r: "1.2", fill: "currentColor", stroke: "none" })] }), t('branchGraph')] })] })] })) : null, newBranchOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: "gbar-modal-wrap", onMouseDown: event => { if (event.target === event.currentTarget)
929
+ return ((0, jsx_runtime_1.jsxs)("span", { className: "gbar", "data-slot-plugin": "dsh-ui-tweaks-gitbar", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", ref: branchRef, className: 'gbar-pill' + (branchOpen ? ' gbar-active' : ''), onClick: toggleBranch, title: dirty ? t('dirty') : t('clean'), "aria-expanded": branchOpen, children: [(0, jsx_runtime_1.jsxs)("svg", { className: "gbar-ico", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "3.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "12.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "5.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.5 5.3v5.4" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 7.3c0 3-3.5 4.8-7.5 3.4" })] }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-text gbar-branch", children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-caret", "aria-hidden": true, children: "\u25BE" })] }), branchOpen ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop", role: "menu", "aria-label": snapshot.branch ?? 'git', ref: branchPopRef, children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop-head", children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-curname", title: dirty ? t('dirty') : t('clean'), children: [(0, jsx_runtime_1.jsxs)("svg", { className: "gbar-bicon", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "3.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "12.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "5.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.5 5.3v5.4" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 7.3c0 3-3.5 4.8-7.5 3.4" })] }), (0, jsx_runtime_1.jsx)("span", { children: snapshot.branch ?? snapshot.detachedHead ?? '—' })] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-state", children: [(0, jsx_runtime_1.jsx)("span", { className: 'gbar-dot ' + (dirty ? 'gbar-dirty' : 'gbar-clean'), "aria-hidden": true }), snapshot.ahead > 0 ? (0, jsx_runtime_1.jsxs)("span", { children: ["\u2191", snapshot.ahead] }) : null, snapshot.behind > 0 ? (0, jsx_runtime_1.jsxs)("span", { children: ["\u2193", snapshot.behind] }) : null] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop-body", children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-sec", children: [t('branchLocal'), branches !== null ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-count", children: branches.local.length }) : null] }), branches === null ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-loading", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }), t('loading')] })) : branches.local.map(name => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-rowwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsxs)("svg", { className: "gbar-bicon", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "3.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "12.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.5 5.3v5.4" }), (0, jsx_runtime_1.jsx)("path", { d: "M11.5 3.7v3a2.6 2.6 0 0 1-2.6 2.6H4.5" })] }), (0, jsx_runtime_1.jsx)("span", { children: name }), name === branches.current ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-check", "aria-hidden": true, children: "\u2713" }) : null] }), name !== branches.current && !isProtectedBranch(name) ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-del' + (confirmDelete === name ? ' gbar-arm' : ''), onClick: () => { deleteBranch(name); }, title: t('branchDelete'), children: confirmDelete === name ? t('branchDeleteConfirm') : ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M2.5 4.5h11" }), (0, jsx_runtime_1.jsx)("path", { d: "M5.5 4.5V3.3c0-.44.36-.8.8-.8h3.4c.44 0 .8.36.8.8v1.2" }), (0, jsx_runtime_1.jsx)("path", { d: "M4 4.5l.6 8.2c.04.5.45.8.95.8h4.9c.5 0 .91-.3.95-.8l.6-8.2" })] })) })) : null] }, name))), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-sec", children: [t('branchRemote'), branches !== null ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-count", children: branches.remote.length }) : null] }), branches?.remote.map(name => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-rowwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsx)("svg", { className: "gbar-bicon", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M5.2 13a3.2 3.2 0 1 1 .5-6.36 4 4 0 0 1 7.75 1.06 2.65 2.65 0 0 1-.55 5.3H5.2Z" }) }), (0, jsx_runtime_1.jsx)("span", { children: shortBranch(name) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-rm", children: name.split('/')[0] })] }), !isProtectedBranch(shortBranch(name)) ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-del' + (confirmDelete === name ? ' gbar-arm' : ''), onClick: () => { deleteRemoteBranch(name); }, title: t('branchRemoteDelete'), children: confirmDelete === name ? t('branchDeleteConfirm') : ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M2.5 4.5h11" }), (0, jsx_runtime_1.jsx)("path", { d: "M5.5 4.5V3.3c0-.44.36-.8.8-.8h3.4c.44 0 .8.36.8.8v1.2" }), (0, jsx_runtime_1.jsx)("path", { d: "M4 4.5l.6 8.2c.04.5.45.8.95.8h4.9c.5 0 .91-.3.95-.8l.6-8.2" })] })) })) : null] }, name)))] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-act", onClick: openNewBranch, children: [(0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M7.4 2.6a1.2 1.2 0 1 1 2.2 0l3.2 1.6a1.2 1.2 0 1 1-1.1 2.1l-2.3-1.2a2.6 2.6 0 0 1-1.1.8l.6 4.2a1.2 1.2 0 1 1-1.7.2l-.6-4.2a2.6 2.6 0 0 1-1.2-.7l-2.9 1.5a1.2 1.2 0 1 1-1.1-2.1l2.9-1.5a2.6 2.6 0 0 1 .2-1.5l-3.2-1.6a1.2 1.2 0 1 1 1.1-2.1z" }) }), t('branchNew')] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-act", onClick: openGraph, children: [(0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M3 1.5v3.4a4.4 4.4 0 0 0 4.4 4.4h5.1" }), (0, jsx_runtime_1.jsx)("path", { d: "M13 1.5v4.9a3.2 3.2 0 0 1-3.2 3.2H3" }), (0, jsx_runtime_1.jsx)("circle", { cx: "3", cy: "1.5", r: "1.2", fill: "currentColor", stroke: "none" }), (0, jsx_runtime_1.jsx)("circle", { cx: "13", cy: "12", r: "1.2", fill: "currentColor", stroke: "none" })] }), t('branchGraph')] })] })] })) : null, newBranchOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: "gbar-modal-wrap", onMouseDown: event => { if (event.target === event.currentTarget)
880
930
  setNewBranchOpen(false); }, children: (0, jsx_runtime_1.jsxs)("div", { className: "gbar-modal", role: "dialog", "aria-label": t('branchNew'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: t('branchNew') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-branch", children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-x", onClick: () => { setNewBranchOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), (0, jsx_runtime_1.jsx)("input", { value: newBranchName, onChange: event => { setNewBranchName(event.target.value); }, onKeyDown: event => { if (event.key === 'Enter')
881
931
  createBranch(); }, placeholder: t('branchNewPlaceholder'), "aria-label": t('branchNew'), autoFocus: true }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-baserow", children: [(0, jsx_runtime_1.jsx)("label", { className: "gbar-baselabel", htmlFor: "gbar-base-dlg", children: t('branchFrom') }), (0, jsx_runtime_1.jsxs)("select", { id: "gbar-base-dlg", className: "gbar-base", value: baseBranch, onChange: event => { setBaseBranch(event.target.value); }, "aria-label": t('branchFrom'), children: [(0, jsx_runtime_1.jsx)("option", { value: "", children: t('branchFromHead') }), branches?.local.map(name => (0, jsx_runtime_1.jsx)("option", { value: name, children: name }, name)), branches?.remote.map(name => (0, jsx_runtime_1.jsx)("option", { value: name, children: name }, name))] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-pushrow", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-chk' + (pushToRemote ? '' : ' gbar-off'), onClick: () => { setPushToRemote(value => !value); }, "aria-label": t('branchPushRemote'), children: pushToRemote ? '✓' : '✕' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-pushlabel", children: t('branchPushRemote') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-foot", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-btn gbar-ghost", onClick: () => { setNewBranchOpen(false); }, children: t('branchCancel') }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-btn gbar-primary", onClick: createBranch, disabled: busy !== null || newBranchName.trim() === '', children: [busy === 'create' || busy === 'create-push' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : null, " ", t('branchCreate')] })] })] }) }), document.body) : null, graphOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: "gbar-modal-wrap", onMouseDown: event => { if (event.target === event.currentTarget)
882
932
  setGraphOpen(false); }, children: (0, jsx_runtime_1.jsxs)("div", { className: "gbar-modal gbar-graph-modal", role: "dialog", "aria-label": t('graphTitle'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: t('graphTitle') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-branch", children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-spacer" }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-x gbar-refresh", onClick: fetchGraph, "aria-label": t('branchRefresh'), title: t('branchRefresh'), disabled: graphBusy, children: graphBusy ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M13.4 8a5.4 5.4 0 1 1-1.6-3.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M13.4 1.5v3h-3" })] })) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-x", onClick: () => { setGraphOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), graph === null ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-graph-empty", children: graphBusy ? t('loading') : t('noChanges') })) : graph.commits.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-graph-empty", children: t('noChanges') })) : ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-graph-table", role: "table", "aria-label": t('graphTitle'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-graph-row gbar-graph-head", role: "row", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-c-hash", role: "columnheader", children: t('graphColCommit') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-subject", role: "columnheader", children: t('graphColSubject') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-author", role: "columnheader", children: t('graphColAuthor') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-date", role: "columnheader", children: t('graphColDate') })] }), graph.commits.map(commit => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-graph-row", role: "row", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-c-hash", role: "cell", children: (0, jsx_runtime_1.jsx)("code", { className: "gbar-hash", children: commit.hash }) }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-c-subject", role: "cell", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-subject", children: commit.subject }), commit.refs !== '' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-refs", children: commit.refs }) : null] }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-author", role: "cell", children: commit.author }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-date", role: "cell", title: commit.date, children: commit.dateRelative })] }, commit.fullHash)))] }))] }) }), document.body) : null, notice !== null ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: 'gbar-notice gbar-' + notice.kind, role: "status", children: notice.text }), document.body) : null] }));
@@ -1027,17 +1077,40 @@ function GitBarDiff({ session, controller, t }) {
1027
1077
  document.addEventListener('mousedown', onDown);
1028
1078
  return () => { document.removeEventListener('mousedown', onDown); };
1029
1079
  }, [diffOpen]);
1030
- // Drag the panel's left edge to resize it.
1080
+ // Drag the panel's left edge to resize it. A press WITHOUT any drag counts
1081
+ // as a click: it snaps the panel to half the screen (or back to the width
1082
+ // it had before expanding), so the edge doubles as a one-button maximize.
1083
+ const prevWidthRef = (0, react_1.useRef)(null);
1084
+ const toggleHalfWidth = () => {
1085
+ const half = Math.round(window.innerWidth / 2);
1086
+ if (diffWidth >= half - 4) {
1087
+ const restore = prevWidthRef.current ?? 440;
1088
+ prevWidthRef.current = null;
1089
+ setDiffWidth(restore);
1090
+ }
1091
+ else {
1092
+ prevWidthRef.current = diffWidth;
1093
+ setDiffWidth(half);
1094
+ }
1095
+ };
1031
1096
  const startResize = (event) => {
1032
1097
  event.preventDefault();
1033
1098
  const startX = event.clientX;
1034
1099
  const startWidth = diffWidth;
1100
+ // Manual drags may reach half the screen too — otherwise an expanded
1101
+ // half-screen panel would instantly clamp back to the old 900px ceiling.
1102
+ const maxWidth = Math.max(900, Math.round(window.innerWidth / 2));
1103
+ let moved = false;
1035
1104
  const onMove = (move) => {
1036
- setDiffWidth(Math.min(900, Math.max(320, startWidth - (move.clientX - startX))));
1105
+ if (!moved && Math.abs(move.clientX - startX) > 3)
1106
+ moved = true;
1107
+ setDiffWidth(Math.min(maxWidth, Math.max(320, startWidth - (move.clientX - startX))));
1037
1108
  };
1038
1109
  const onUp = () => {
1039
1110
  window.removeEventListener('pointermove', onMove);
1040
1111
  window.removeEventListener('pointerup', onUp);
1112
+ if (!moved)
1113
+ toggleHalfWidth();
1041
1114
  };
1042
1115
  window.addEventListener('pointermove', onMove);
1043
1116
  window.addEventListener('pointerup', onUp);
@@ -1100,11 +1173,16 @@ function GitBarDiff({ session, controller, t }) {
1100
1173
  if (snapshot.clean)
1101
1174
  return null;
1102
1175
  const dirty = !snapshot.clean;
1103
- return ((0, jsx_runtime_1.jsxs)("span", { className: "gbar", "data-slot-plugin": "dsh-ui-tweaks-gitbar", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-pill' + (diffOpen ? ' gbar-active' : ''), onClick: openDiff, title: t('diffTitle'), children: [(0, jsx_runtime_1.jsx)("svg", { className: "gbar-ico", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M5 1.5h4l3 3V13a1.5 1.5 0 0 1-1.5 1.5h-5A1.5 1.5 0 0 1 4 13V3A1.5 1.5 0 0 1 5 1.5zM5 2.5V13h5V5.2L8.8 3.5H5zm.5 4.5a.75.75 0 1 1 0 1.5.75.75 0 0 1 0-1.5zm3.25.25h-1.5v1.5h1.5V7.25zm.25 2.5H5.75v1.5h3.25v-1.5z" }) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-text", children: dirty ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-add", children: ["+", snapshot.totalAdded] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-del", children: ["\u2212", snapshot.totalDeleted] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-meta", children: ["\u00B7 ", snapshot.files.length, " ", t('diffFiles')] })] })) : ((0, jsx_runtime_1.jsx)("span", { className: "gbar-hint", children: t('clean') })) })] }), diffOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsxs)("div", { className: "gbar-side", role: "dialog", "aria-label": t('diffTitle'), style: { width: `${diffWidth}px`, top: `${panelTop}px` }, children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-resize", onPointerDown: startResize, title: "\u62D6\u52A8\u8C03\u6574\u5BBD\u5EA6" }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: diffPath ?? t('diffTitle') }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-sub", children: [snapshot.files.length, " ", t('diffFiles'), " \u00B7 +", snapshot.totalAdded, " \u2212", snapshot.totalDeleted] }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-spacer" }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-seg", role: "group", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: diffMode === 'hunk' ? 'gbar-on' : '', onClick: () => { switchDiffMode('hunk'); }, children: t('diffOnly') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: diffMode === 'full' ? 'gbar-on' : '', onClick: () => { switchDiffMode('full'); }, children: t('diffFull') })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-side-x", onClick: () => { setDiffOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-body", children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-files", style: filesHeight === null
1176
+ return ((0, jsx_runtime_1.jsxs)("span", { className: "gbar", "data-slot-plugin": "dsh-ui-tweaks-gitbar", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-pill' + (diffOpen ? ' gbar-active' : ''), onClick: openDiff, title: t('diffTitle'), children: [(0, jsx_runtime_1.jsx)("svg", { className: "gbar-ico", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M5 1.5h4l3 3V13a1.5 1.5 0 0 1-1.5 1.5h-5A1.5 1.5 0 0 1 4 13V3A1.5 1.5 0 0 1 5 1.5zM5 2.5V13h5V5.2L8.8 3.5H5zm.5 4.5a.75.75 0 1 1 0 1.5.75.75 0 0 1 0-1.5zm3.25.25h-1.5v1.5h1.5V7.25zm.25 2.5H5.75v1.5h3.25v-1.5z" }) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-text", children: dirty ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-add", children: ["+", snapshot.totalAdded] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-del", children: ["\u2212", snapshot.totalDeleted] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-meta", children: ["\u00B7 ", snapshot.files.length, " ", t('diffFiles')] })] })) : ((0, jsx_runtime_1.jsx)("span", { className: "gbar-hint", children: t('clean') })) })] }), diffOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsxs)("div", { className: "gbar-side", role: "dialog", "aria-label": t('diffTitle'), style: { width: `${diffWidth}px`, top: `${panelTop}px` }, children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-resize", onPointerDown: startResize, title: "\u62D6\u52A8\u8C03\u6574\u5BBD\u5EA6 \u00B7 \u70B9\u51FB\u5C55\u5F00\u5230\u534A\u5C4F" }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: diffPath ?? t('diffTitle') }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-sub", children: [snapshot.files.length, " ", t('diffFiles'), " \u00B7 ", (0, jsx_runtime_1.jsxs)("span", { className: "gbar-a", children: ["+", snapshot.totalAdded] }), " ", (0, jsx_runtime_1.jsxs)("span", { className: "gbar-d", children: ["\u2212", snapshot.totalDeleted] })] }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-spacer" }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-seg", role: "group", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: diffMode === 'hunk' ? 'gbar-on' : '', onClick: () => { switchDiffMode('hunk'); }, children: t('diffOnly') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: diffMode === 'full' ? 'gbar-on' : '', onClick: () => { switchDiffMode('full'); }, children: t('diffFull') })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-side-x", onClick: () => { setDiffOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-body", children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-files", style: filesHeight === null
1104
1177
  ? { maxHeight: FILES_AUTO_MAX }
1105
1178
  : { height: filesHeight, maxHeight: SECTION_MAX }, children: snapshot.files.map(file => {
1106
1179
  const isExcluded = excluded.has(file.path);
1107
- return ((0, jsx_runtime_1.jsxs)("div", { className: 'gbar-file' + (diffPath === file.path ? ' gbar-on' : '') + (isExcluded ? ' gbar-excl' : ''), children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-chk' + (isExcluded ? ' gbar-off' : ''), onClick: () => { toggleExclude(file.path); }, "aria-label": isExcluded ? t('excludeFile') : t('includeFile'), children: isExcluded ? '✕' : '✓' }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-file-main", onClick: () => { selectDiffFile(file.path); }, children: [(0, jsx_runtime_1.jsx)("span", { className: 'gbar-st ' + statusClass(file.status), children: statusLetter(file.status) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-path", children: file.path }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-nums", children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-a", children: ["+", file.added] }), " ", (0, jsx_runtime_1.jsxs)("span", { className: "gbar-d", children: ["\u2212", file.deleted] })] })] })] }, file.path));
1180
+ // Split the path so the directory renders dim and the filename
1181
+ // bright — the eye scans by filename, not by folder.
1182
+ const slash = file.path.lastIndexOf('/');
1183
+ const dir = slash >= 0 ? file.path.slice(0, slash + 1) : '';
1184
+ const base = slash >= 0 ? file.path.slice(slash + 1) : file.path;
1185
+ return ((0, jsx_runtime_1.jsxs)("div", { className: 'gbar-file' + (diffPath === file.path ? ' gbar-on' : '') + (isExcluded ? ' gbar-excl' : ''), children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-chk' + (isExcluded ? ' gbar-off' : ''), onClick: () => { toggleExclude(file.path); }, "aria-label": isExcluded ? t('excludeFile') : t('includeFile'), children: isExcluded ? '✕' : '✓' }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-file-main", onClick: () => { selectDiffFile(file.path); }, title: file.path, children: [(0, jsx_runtime_1.jsx)("span", { className: 'gbar-st ' + statusClass(file.status), children: statusLetter(file.status) }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-path", children: [dir !== '' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-dir", children: dir }) : null, (0, jsx_runtime_1.jsx)("span", { children: base })] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-nums", children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-a", children: ["+", file.added] }), " ", (0, jsx_runtime_1.jsxs)("span", { className: "gbar-d", children: ["\u2212", file.deleted] })] })] })] }, file.path));
1108
1186
  }) }), (0, jsx_runtime_1.jsx)("div", { className: 'gbar-vsplit' + (dragging === 'files' ? ' gbar-dragging' : ''), role: "separator", "aria-orientation": "horizontal", title: "\u62D6\u52A8\u8C03\u6574\u6587\u4EF6\u5217\u8868\u9AD8\u5EA6\uFF08\u53CC\u51FB\u590D\u4F4D\uFF09", onPointerDown: event => { startVResize('files', event); }, onDoubleClick: () => { setFilesHeight(null); } }), diff === null ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-diff", children: (0, jsx_runtime_1.jsx)("div", { className: "gbar-empty", children: t('loading') }) })) : diff.lines.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-diff", children: (0, jsx_runtime_1.jsx)("div", { className: "gbar-empty", children: t('noChanges') }) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-diff", children: [diff.lines.map((line, i) => ((0, jsx_runtime_1.jsxs)("div", { className: 'gbar-line gbar-' + line.type, children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-ln", children: line.old ?? '' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-ln", children: line.new ?? '' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-code", children: line.text })] }, i))), diff.truncated ? (0, jsx_runtime_1.jsx)("div", { className: "gbar-empty", children: "\u2026" }) : null] })), dirty ? ((0, jsx_runtime_1.jsx)("div", { className: 'gbar-vsplit' + (dragging === 'commit' ? ' gbar-dragging' : ''), role: "separator", "aria-orientation": "horizontal", title: "\u62D6\u52A8\u8C03\u6574\u63D0\u4EA4\u533A\u9AD8\u5EA6\uFF08\u53CC\u51FB\u590D\u4F4D\uFF09", onPointerDown: event => { startVResize('commit', event); }, onDoubleClick: () => { setCommitHeight(null); } })) : null] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-foot", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-dot" }), snapshot.branch ?? '—', " \u00B7 ", dirty ? t('dirty') : t('clean')] }), dirty ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-commit", style: commitHeight === null ? undefined : { height: commitHeight, maxHeight: SECTION_MAX }, children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-crow", children: (0, jsx_runtime_1.jsx)("textarea", { value: message, onChange: event => { setMessage(event.target.value); }, onKeyDown: event => {
1109
1187
  // Enter commits; Shift+Enter adds a line, now that this field
1110
1188
  // can be dragged tall enough for a multi-line message.
@@ -2020,27 +2098,18 @@ function registerInitCommand(ctx) {
2020
2098
  onSelect: async (option, session) => {
2021
2099
  const prompt = option.id === 'en' ? INIT_PROMPT_EN : INIT_PROMPT_ZH;
2022
2100
  const scoped = ctx.sessions.scope(session.sessionId);
2023
- try {
2024
- if (scoped === undefined)
2025
- throw new Error(`session ${session.sessionId} is not scoped`);
2026
- await scoped.conversation.send(prompt);
2027
- }
2028
- catch (error) {
2029
- // Surface through the session composer's notice bar when reachable;
2030
- // fall back to the console for pruned scopes.
2031
- const text = `${t('initFailed')}: ${error instanceof Error ? error.message : String(error)}`;
2032
- if (scoped !== undefined) {
2033
- try {
2034
- ctx.conversation.input.for(scoped).notify('error', text);
2035
- }
2036
- catch {
2037
- console.error(`[dsh-ui-tweaks] ${text}`);
2038
- }
2039
- }
2040
- else {
2041
- console.error(`[dsh-ui-tweaks] ${text}`);
2042
- }
2101
+ if (scoped === undefined) {
2102
+ console.error(`[dsh-ui-tweaks] ${t('initFailed')}: session ${session.sessionId} is not scoped`);
2103
+ return;
2043
2104
  }
2105
+ // Route through the session's input facade (draft + submit) instead of
2106
+ // a bare conversation.send: the hub's own send choreography then
2107
+ // handles first-message materialization for a brand-new session, plus
2108
+ // queue/steer policy while a turn is running. A direct send cannot
2109
+ // start an unmaterialized session and fails silently there.
2110
+ const input = ctx.conversation.input.for(scoped);
2111
+ input.setDraft(prompt);
2112
+ input.submit();
2044
2113
  },
2045
2114
  },
2046
2115
  });
@@ -2572,6 +2641,17 @@ const react_dom_1 = require("react-dom");
2572
2641
  exports.TIMELINE_PROJECTION_KEY = 'dshChatTimeline';
2573
2642
  /** Gap between the rail and the message area's right edge, in px. */
2574
2643
  const EDGE_GAP = 12;
2644
+ /** Expanded panel width — keep in sync with `.dutl-wrap.dutl-show` (240px). */
2645
+ const PANEL_WIDTH = 240;
2646
+ /**
2647
+ * Horizontal slot of the detail bubble: this many px left of the EXPANDED
2648
+ * panel's left edge. Computed from constants instead of measuring the hovered
2649
+ * row — the row's rect mid-expansion-animation (first hover!) reflects the
2650
+ * still-narrow panel, which made the bubble hug the rail on first hover and
2651
+ * then jump left once the animation settled. A constant slot is stable from
2652
+ * the very first frame.
2653
+ */
2654
+ const BUBBLE_GAP = 14;
2575
2655
  const NOOP_STORE = {
2576
2656
  getSnapshot: () => undefined,
2577
2657
  subscribe: () => () => { },
@@ -2965,19 +3045,25 @@ function TimelineRail({ useProjection, sessionId, sessionsService, controller, t
2965
3045
  }, [sessionId, messages.length, source]);
2966
3046
  if (!enabled || sessionId === undefined || messages.length < 2)
2967
3047
  return null;
3048
+ const railRight = anchor === null ? EDGE_GAP : anchor.right;
2968
3049
  const railStyle = anchor === null
2969
3050
  ? { top: '50%', right: EDGE_GAP, transform: 'translateY(-50%)' }
2970
3051
  : { top: anchor.top, right: anchor.right, transform: 'translateY(-50%)' };
3052
+ // Stable horizontal slot: always left of the fully-expanded panel, never
3053
+ // measured from the animating rows (see BUBBLE_GAP above).
3054
+ const bubbleStyle = { top: bubble === null ? 0 : bubble.top, right: railRight + PANEL_WIDTH + BUBBLE_GAP };
2971
3055
  return (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "dutl-nav", role: "navigation", "aria-label": t('railLabel'), onMouseEnter: () => { setShow(true); }, onMouseLeave: () => { setShow(false); }, style: railStyle, children: (0, jsx_runtime_1.jsx)("div", { className: 'dutl-wrap' + (show ? ' dutl-show' : ''), children: (0, jsx_runtime_1.jsx)("div", { className: "dutl-page", ref: pageRef, children: messages.map((m, i) => {
2972
3056
  const key = anchorKeyOf(m);
2973
3057
  return ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'dutl-item' + (activeIndex === i ? ' dutl-active' : ''), "aria-label": `${t('roleUser')}: ${m.text.slice(0, 60) || t('noText')}`, "aria-current": activeIndex === i ? 'location' : undefined, onClick: () => { if (key !== undefined)
2974
3058
  void jumpToMessage(sessionsService, sessionId, key).catch(() => { }); }, onMouseEnter: (event) => {
3059
+ // Vertical: follow the hovered row (clamped into the
3060
+ // viewport). Horizontal: the constant slot next to the
3061
+ // expanded panel — identical on first hover and after.
2975
3062
  const rect = event.currentTarget.getBoundingClientRect();
2976
3063
  const top = Math.min(Math.max(rect.top + rect.height / 2, 150), window.innerHeight - 150);
2977
- const right = Math.max(0, window.innerWidth - rect.left + 14);
2978
- setBubble({ top, right, entry: m });
3064
+ setBubble({ top, entry: m });
2979
3065
  }, onMouseLeave: () => { setBubble(null); }, children: [(0, jsx_runtime_1.jsx)("span", { className: 'dutl-title' + (show ? ' dutl-show' : ''), children: m.text === '' ? t('noText') : m.text }), (0, jsx_runtime_1.jsx)("span", { className: "dutl-ind", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("span", { className: "dutl-line" }) })] }, m.seq));
2980
- }) }) }) }), bubble !== null && show ? ((0, jsx_runtime_1.jsxs)("div", { className: "dutl-bubble", style: { top: bubble.top, right: bubble.right }, role: "tooltip", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dutl-bubble-head", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dutl-bubble-user", children: [(0, jsx_runtime_1.jsx)("span", { className: "dutl-bubble-dot" }), t('roleUser')] }), (0, jsx_runtime_1.jsx)("span", { className: "dutl-bubble-time", children: formatTime(bubble.entry.time) })] }), (0, jsx_runtime_1.jsx)("div", { className: "dutl-bubble-text", children: bubble.entry.text === '' ? t('noText') : bubble.entry.text })] })) : null] }), document.body);
3066
+ }) }) }) }), bubble !== null && show ? ((0, jsx_runtime_1.jsxs)("div", { className: "dutl-bubble", style: bubbleStyle, role: "tooltip", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dutl-bubble-head", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dutl-bubble-user", children: [(0, jsx_runtime_1.jsx)("span", { className: "dutl-bubble-dot" }), t('roleUser')] }), (0, jsx_runtime_1.jsx)("span", { className: "dutl-bubble-time", children: formatTime(bubble.entry.time) })] }), (0, jsx_runtime_1.jsx)("div", { className: "dutl-bubble-text", children: bubble.entry.text === '' ? t('noText') : bubble.entry.text })] })) : null] }), document.body);
2981
3067
  }
2982
3068
  };
2983
3069
  function __resolve(from, request) {