dsh-diff-approval 0.9.0 → 0.11.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.
- package/README.md +4 -3
- package/README.zh.md +4 -3
- package/docs/images/pending-panel.png +0 -0
- package/docs/images/pending-panel.zh.png +0 -0
- package/lib/client.js +747 -161
- package/lib/index.js +39 -8
- package/lib/types/client/PendingPanel.d.ts +1 -0
- package/lib/types/client/SettingsTab.d.ts +5 -4
- package/lib/types/client/locales.d.ts +10 -0
- package/lib/types/client/settings.d.ts +19 -0
- package/lib/types/client/whole-file-diff.d.ts +4 -1
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -643,15 +643,21 @@ window.__ModuleLoader__.load({
|
|
|
643
643
|
* Compute the whole-file view between two contents. The context budget is the
|
|
644
644
|
* side lengths, so every hunk covers the file and unchanged lines survive as
|
|
645
645
|
* context rows; the `` patch marker is annotation
|
|
646
|
-
* and never becomes a row.
|
|
646
|
+
* and never becomes a row. Both sides are line-ending normalized (`\r\n?` →
|
|
647
|
+
* `\n`) first, so a repo baseline stored with one EOL and a worktree with
|
|
648
|
+
* another never show as a whole-file delete+add — the diff is about approved
|
|
649
|
+
* content, not line-ending noise.
|
|
647
650
|
* @param oldText - the file content before the pending change.
|
|
648
651
|
* @param newText - the file content after the pending change.
|
|
649
652
|
* @returns the complete row list with totals.
|
|
650
653
|
*/
|
|
651
654
|
function computeWholeFileDiff(oldText, newText) {
|
|
655
|
+
oldText = oldText.replace(/\r\n?/g, "\n");
|
|
656
|
+
newText = newText.replace(/\r\n?/g, "\n");
|
|
652
657
|
const oldLines = contentLines(oldText);
|
|
653
658
|
const newLines = contentLines(newText);
|
|
654
|
-
const
|
|
659
|
+
const context = Math.max(1, oldLines.length, newLines.length);
|
|
660
|
+
const patch = structuredPatch("", "", oldText, newText, void 0, void 0, { context });
|
|
655
661
|
const rows = [];
|
|
656
662
|
let removed = 0;
|
|
657
663
|
let added = 0;
|
|
@@ -11624,6 +11630,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11624
11630
|
/** Client preferences for the review panel, persisted in localStorage. */
|
|
11625
11631
|
const PASTE_ON_COPY_KEY = "diff-approval:paste-on-copy";
|
|
11626
11632
|
const IMPORT_UNTRACKED_KEY = "diff-approval:import-untracked";
|
|
11633
|
+
const TAB_WIDTH_KEY = "diff-approval:tab-size";
|
|
11634
|
+
const WRAP_PREFIX = "diff-approval:wrap:";
|
|
11627
11635
|
/**
|
|
11628
11636
|
* Whether copying a reference should also paste it into the chat input and
|
|
11629
11637
|
* focus it. Defaults to on; only an explicit `'0'` disables it.
|
|
@@ -11650,9 +11658,37 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11650
11658
|
function setIncludeUntrackedEnabled(value) {
|
|
11651
11659
|
localStorage.setItem(IMPORT_UNTRACKED_KEY, value ? "1" : "0");
|
|
11652
11660
|
}
|
|
11661
|
+
/**
|
|
11662
|
+
* Whether lines wrap (auto-wrap) in the diff for one highlight language.
|
|
11663
|
+
* Defaults to off; only an explicit `'1'` enables it. Stored per language, so
|
|
11664
|
+
* a language's preference never leaks into another's.
|
|
11665
|
+
* @param lang - the highlight language (or `''` for the auto/default bucket).
|
|
11666
|
+
* @returns whether lines wrap.
|
|
11667
|
+
*/
|
|
11668
|
+
function wrapEnabled(lang) {
|
|
11669
|
+
return localStorage.getItem(`${WRAP_PREFIX}${lang}`) === "1";
|
|
11670
|
+
}
|
|
11671
|
+
/** Persist the per-language auto-wrap preference. */
|
|
11672
|
+
function setWrapEnabled(lang, value) {
|
|
11673
|
+
localStorage.setItem(`${WRAP_PREFIX}${lang}`, value ? "1" : "0");
|
|
11674
|
+
}
|
|
11675
|
+
/**
|
|
11676
|
+
* The diff's tab width in spaces. Defaults to 4; the settings UI offers 2/4/8,
|
|
11677
|
+
* but any positive integer is accepted. This drives both the rendered
|
|
11678
|
+
* `tab-size` and the wrapped-line tab measurement, so they always agree.
|
|
11679
|
+
* @returns the number of spaces one tab advances.
|
|
11680
|
+
*/
|
|
11681
|
+
function tabWidth() {
|
|
11682
|
+
const value = Number.parseInt(localStorage.getItem(TAB_WIDTH_KEY) ?? "", 10);
|
|
11683
|
+
return Number.isInteger(value) && value > 0 ? value : 4;
|
|
11684
|
+
}
|
|
11685
|
+
/** Persist the diff's tab width (in spaces). */
|
|
11686
|
+
function setTabWidth(value) {
|
|
11687
|
+
localStorage.setItem(TAB_WIDTH_KEY, String(value));
|
|
11688
|
+
}
|
|
11653
11689
|
//#endregion
|
|
11654
11690
|
//#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
|
|
11655
|
-
const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 4px);height:42px;margin:4px -2px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badge:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_fullscreenBackdrop{z-index:29;background:var(--dsw-specific-sidebar-fill);position:fixed;inset:0}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_settingsPage{padding:8px 12px}.F1KBNa_settingsRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.F1KBNa_settingsRowTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsRowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsSelector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelectorChevron{flex:none}.F1KBNa_states{flex-direction:column;flex:1;min-height:0;padding:4px 12px 12px;display:flex;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:240px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:auto}.F1KBNa_bulkActions{flex:none;gap:6px;padding-top:8px;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.F1KBNa_resizeHandle{cursor:col-resize;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_noteCentered{text-align:center;margin:auto}.F1KBNa_emptyState{flex-direction:column;align-items:center;gap:10px;margin:auto;display:flex}.F1KBNa_importButton{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:5px 14px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_importButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_importButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_importNote{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_rowFailed{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_actionError{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);flex:1;font-size:12px;line-height:18px;overflow:hidden}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_actionQuietDisabled:disabled{cursor:pointer;color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1);background:0 0}.F1KBNa_actionPrimary.F1KBNa_actionQuietDisabled:disabled{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:1}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);cursor:text;outline:none;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:9px;padding:5px;display:flex;position:absolute;right:8px}.F1KBNa_blockPosition{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;margin-top:1px;margin-left:7px;font-size:12px;line-height:16px}.F1KBNa_searchBar{z-index:3;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;top:8px;right:8px}.F1KBNa_searchInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:150px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_searchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchCount{text-align:center;min-width:34px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:16px}.F1KBNa_diffBody [data-diff-search=hit]{background-image:linear-gradient(#facc1529,#facc1529)}.F1KBNa_diffBody [data-diff-search=current]{background-image:linear-gradient(#facc1552,#facc1552)}.F1KBNa_blockFlash{z-index:1;box-sizing:border-box;border:2px solid var(--dsw-alias-state-business-primary);pointer-events:none;border-radius:4px;animation:1s ease-out forwards F1KBNa_diffFlash;position:absolute;left:0;right:0}@keyframes F1KBNa_diffFlash{0%{opacity:1}to{opacity:0}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}";
|
|
11691
|
+
const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 4px);height:42px;margin:4px -2px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badge:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_fullscreenBackdrop{z-index:29;background:var(--dsw-specific-sidebar-fill);position:fixed;inset:0}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_settingsPage{padding:8px 12px}.F1KBNa_settingsRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.F1KBNa_settingsRowTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsRowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsSelector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelectorChevron{flex:none}.F1KBNa_states{flex-direction:column;flex:1;min-height:0;padding:4px 12px 12px;display:flex;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex;position:relative}.F1KBNa_fileListFloat{z-index:40;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;flex-direction:column;padding:6px 8px 10px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:240px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:auto}.F1KBNa_bulkActions{flex:none;gap:6px;padding-top:8px;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.F1KBNa_resizeHandle{cursor:col-resize;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_noteCentered{text-align:center;margin:auto}.F1KBNa_emptyState{flex-direction:column;align-items:center;gap:10px;margin:auto;display:flex}.F1KBNa_importButton{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:5px 14px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_importButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_importButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_importNote{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_rowFailed{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_actionError{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);flex:1;font-size:12px;line-height:18px;overflow:hidden}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_actionQuietDisabled:disabled{cursor:pointer;color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1);background:0 0}.F1KBNa_actionPrimary.F1KBNa_actionQuietDisabled:disabled{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:1}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);cursor:text;outline:none;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:9px;padding:5px;display:flex;position:absolute;right:8px}.F1KBNa_blockPosition{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;margin-top:1px;margin-left:7px;font-size:12px;line-height:16px}.F1KBNa_searchBar{z-index:3;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;top:8px;right:8px}.F1KBNa_searchInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:150px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_searchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchCount{text-align:center;min-width:34px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:16px}.F1KBNa_diffBody [data-diff-search=hit]{background-image:linear-gradient(#facc1529,#facc1529)}.F1KBNa_diffBody [data-diff-search=current]{background-image:linear-gradient(#facc1552,#facc1552)}.F1KBNa_blockFlash{z-index:1;box-sizing:border-box;border:2px solid var(--dsw-alias-state-business-primary);pointer-events:none;border-radius:4px;animation:1s ease-out forwards F1KBNa_diffFlash;position:absolute;left:0;right:0}@keyframes F1KBNa_diffFlash{0%{opacity:1}to{opacity:0}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_wrap .F1KBNa_line{height:auto;min-height:22px}.F1KBNa_subline{white-space:pre;height:22px;line-height:22px;display:block;overflow:hidden}.F1KBNa_wrapActive{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_wrapActive:hover{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}";
|
|
11656
11692
|
const tagId = "dsh-diff-approval/PendingPanel.module.css";
|
|
11657
11693
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
11658
11694
|
const tag = document.createElement("style");
|
|
@@ -11662,95 +11698,99 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11662
11698
|
document.head.appendChild(tag);
|
|
11663
11699
|
}
|
|
11664
11700
|
var PendingPanel_module_css_default = {
|
|
11665
|
-
"rows": "F1KBNa_rows",
|
|
11666
|
-
"flexSpacer": "F1KBNa_flexSpacer",
|
|
11667
|
-
"importNote": "F1KBNa_importNote",
|
|
11668
|
-
"detailEmpty": "F1KBNa_detailEmpty",
|
|
11669
11701
|
"divergedHint": "F1KBNa_divergedHint",
|
|
11670
11702
|
"detail": "F1KBNa_detail",
|
|
11703
|
+
"fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
|
|
11704
|
+
"diffBody": "F1KBNa_diffBody",
|
|
11705
|
+
"langSelect": "F1KBNa_langSelect",
|
|
11671
11706
|
"note": "F1KBNa_note",
|
|
11672
|
-
"
|
|
11673
|
-
"
|
|
11674
|
-
"searchCount": "F1KBNa_searchCount",
|
|
11675
|
-
"footerButtons": "F1KBNa_footerButtons",
|
|
11676
|
-
"settingsRowTitle": "F1KBNa_settingsRowTitle",
|
|
11677
|
-
"title": "F1KBNa_title",
|
|
11678
|
-
"hint": "F1KBNa_hint",
|
|
11707
|
+
"code": "F1KBNa_code",
|
|
11708
|
+
"diffHeader": "F1KBNa_diffHeader",
|
|
11679
11709
|
"overviewRuler": "F1KBNa_overviewRuler",
|
|
11710
|
+
"readError": "F1KBNa_readError",
|
|
11680
11711
|
"gutter": "F1KBNa_gutter",
|
|
11681
|
-
"
|
|
11682
|
-
"badge": "F1KBNa_badge",
|
|
11683
|
-
"badgeLabel": "F1KBNa_badgeLabel",
|
|
11684
|
-
"rail": "F1KBNa_rail",
|
|
11685
|
-
"diffBody": "F1KBNa_diffBody",
|
|
11686
|
-
"rowMeta": "F1KBNa_rowMeta",
|
|
11687
|
-
"resizeHandle": "F1KBNa_resizeHandle",
|
|
11688
|
-
"kindTag": "F1KBNa_kindTag",
|
|
11689
|
-
"states": "F1KBNa_states",
|
|
11690
|
-
"panel": "F1KBNa_panel",
|
|
11691
|
-
"diff": "F1KBNa_diff",
|
|
11692
|
-
"statusAction": "F1KBNa_statusAction",
|
|
11693
|
-
"blockPosition": "F1KBNa_blockPosition",
|
|
11694
|
-
"notice": "F1KBNa_notice",
|
|
11695
|
-
"noticeText": "F1KBNa_noticeText",
|
|
11696
|
-
"rowFailed": "F1KBNa_rowFailed",
|
|
11697
|
-
"context": "F1KBNa_context",
|
|
11712
|
+
"markerAdd": "F1KBNa_markerAdd",
|
|
11698
11713
|
"del": "F1KBNa_del",
|
|
11699
|
-
"
|
|
11700
|
-
"
|
|
11701
|
-
"
|
|
11702
|
-
"diffStats": "F1KBNa_diffStats",
|
|
11703
|
-
"actionError": "F1KBNa_actionError",
|
|
11714
|
+
"fileList": "F1KBNa_fileList",
|
|
11715
|
+
"delCount": "F1KBNa_delCount",
|
|
11716
|
+
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
11704
11717
|
"blockFlash": "F1KBNa_blockFlash",
|
|
11705
|
-
"
|
|
11706
|
-
"
|
|
11707
|
-
"
|
|
11708
|
-
"
|
|
11709
|
-
"
|
|
11710
|
-
"
|
|
11711
|
-
"listScroll": "F1KBNa_listScroll",
|
|
11712
|
-
"expandExpanded": "F1KBNa_expandExpanded",
|
|
11713
|
-
"lines": "F1KBNa_lines",
|
|
11714
|
-
"readError": "F1KBNa_readError",
|
|
11715
|
-
"layer": "F1KBNa_layer",
|
|
11718
|
+
"context": "F1KBNa_context",
|
|
11719
|
+
"fileListFloat": "F1KBNa_fileListFloat",
|
|
11720
|
+
"diff": "F1KBNa_diff",
|
|
11721
|
+
"rowMeta": "F1KBNa_rowMeta",
|
|
11722
|
+
"panel": "F1KBNa_panel",
|
|
11723
|
+
"title": "F1KBNa_title",
|
|
11716
11724
|
"expand": "F1KBNa_expand",
|
|
11717
|
-
"
|
|
11718
|
-
"
|
|
11719
|
-
"fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
|
|
11720
|
-
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
11721
|
-
"diffHeader": "F1KBNa_diffHeader",
|
|
11722
|
-
"rowPath": "F1KBNa_rowPath",
|
|
11725
|
+
"lines": "F1KBNa_lines",
|
|
11726
|
+
"missingHint": "F1KBNa_missingHint",
|
|
11723
11727
|
"headerActions": "F1KBNa_headerActions",
|
|
11724
|
-
"
|
|
11728
|
+
"settingsRowDesc": "F1KBNa_settingsRowDesc",
|
|
11729
|
+
"close": "F1KBNa_close",
|
|
11730
|
+
"iconAction": "F1KBNa_iconAction",
|
|
11731
|
+
"rail": "F1KBNa_rail",
|
|
11732
|
+
"wrap": "F1KBNa_wrap",
|
|
11725
11733
|
"diffPath": "F1KBNa_diffPath",
|
|
11726
|
-
"
|
|
11727
|
-
"
|
|
11728
|
-
"
|
|
11729
|
-
"
|
|
11730
|
-
"
|
|
11731
|
-
"
|
|
11732
|
-
"
|
|
11733
|
-
"searchInput": "F1KBNa_searchInput",
|
|
11734
|
-
"markerAdd": "F1KBNa_markerAdd",
|
|
11734
|
+
"importNote": "F1KBNa_importNote",
|
|
11735
|
+
"missing": "F1KBNa_missing",
|
|
11736
|
+
"footerButtons": "F1KBNa_footerButtons",
|
|
11737
|
+
"resizeHandle": "F1KBNa_resizeHandle",
|
|
11738
|
+
"line": "F1KBNa_line",
|
|
11739
|
+
"kindTag": "F1KBNa_kindTag",
|
|
11740
|
+
"bulkActions": "F1KBNa_bulkActions",
|
|
11735
11741
|
"vSpacer": "F1KBNa_vSpacer",
|
|
11736
|
-
"settingsRowText": "F1KBNa_settingsRowText",
|
|
11737
|
-
"missingHint": "F1KBNa_missingHint",
|
|
11738
|
-
"group": "F1KBNa_group",
|
|
11739
11742
|
"emptyState": "F1KBNa_emptyState",
|
|
11740
|
-
"
|
|
11741
|
-
"
|
|
11742
|
-
"
|
|
11743
|
+
"badgeLabel": "F1KBNa_badgeLabel",
|
|
11744
|
+
"rowFailed": "F1KBNa_rowFailed",
|
|
11745
|
+
"layer": "F1KBNa_layer",
|
|
11746
|
+
"badgeCount": "F1KBNa_badgeCount",
|
|
11747
|
+
"noteCentered": "F1KBNa_noteCentered",
|
|
11743
11748
|
"settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
|
|
11744
|
-
"
|
|
11745
|
-
"
|
|
11746
|
-
"
|
|
11749
|
+
"importButton": "F1KBNa_importButton",
|
|
11750
|
+
"header": "F1KBNa_header",
|
|
11751
|
+
"action": "F1KBNa_action",
|
|
11752
|
+
"actionError": "F1KBNa_actionError",
|
|
11753
|
+
"flexSpacer": "F1KBNa_flexSpacer",
|
|
11754
|
+
"settingsRowText": "F1KBNa_settingsRowText",
|
|
11755
|
+
"actionQuietDisabled": "F1KBNa_actionQuietDisabled",
|
|
11756
|
+
"blockActions": "F1KBNa_blockActions",
|
|
11757
|
+
"listScroll": "F1KBNa_listScroll",
|
|
11758
|
+
"hint": "F1KBNa_hint",
|
|
11759
|
+
"kindHint": "F1KBNa_kindHint",
|
|
11760
|
+
"diffActions": "F1KBNa_diffActions",
|
|
11761
|
+
"expandExpanded": "F1KBNa_expandExpanded",
|
|
11747
11762
|
"settingsRow": "F1KBNa_settingsRow",
|
|
11748
|
-
"
|
|
11763
|
+
"blockPosition": "F1KBNa_blockPosition",
|
|
11764
|
+
"statusAction": "F1KBNa_statusAction",
|
|
11765
|
+
"searchBar": "F1KBNa_searchBar",
|
|
11766
|
+
"searchInput": "F1KBNa_searchInput",
|
|
11767
|
+
"rows": "F1KBNa_rows",
|
|
11768
|
+
"statusBar": "F1KBNa_statusBar",
|
|
11749
11769
|
"settingsPage": "F1KBNa_settingsPage",
|
|
11770
|
+
"overviewMarker": "F1KBNa_overviewMarker",
|
|
11771
|
+
"add": "F1KBNa_add",
|
|
11772
|
+
"langLabel": "F1KBNa_langLabel",
|
|
11773
|
+
"notice": "F1KBNa_notice",
|
|
11774
|
+
"states": "F1KBNa_states",
|
|
11775
|
+
"rowPath": "F1KBNa_rowPath",
|
|
11776
|
+
"searchCount": "F1KBNa_searchCount",
|
|
11777
|
+
"diffStats": "F1KBNa_diffStats",
|
|
11778
|
+
"badge": "F1KBNa_badge",
|
|
11779
|
+
"markerDel": "F1KBNa_markerDel",
|
|
11750
11780
|
"addCount": "F1KBNa_addCount",
|
|
11751
|
-
"
|
|
11752
|
-
"
|
|
11753
|
-
"
|
|
11781
|
+
"settingsSelector": "F1KBNa_settingsSelector",
|
|
11782
|
+
"diffFlash": "F1KBNa_diffFlash",
|
|
11783
|
+
"subline": "F1KBNa_subline",
|
|
11784
|
+
"split": "F1KBNa_split",
|
|
11785
|
+
"detailEmpty": "F1KBNa_detailEmpty",
|
|
11786
|
+
"noticeButton": "F1KBNa_noticeButton",
|
|
11787
|
+
"row": "F1KBNa_row",
|
|
11788
|
+
"wrapActive": "F1KBNa_wrapActive",
|
|
11789
|
+
"settingsRowTitle": "F1KBNa_settingsRowTitle",
|
|
11790
|
+
"group": "F1KBNa_group",
|
|
11791
|
+
"rowHead": "F1KBNa_rowHead",
|
|
11792
|
+
"actionPrimary": "F1KBNa_actionPrimary",
|
|
11793
|
+
"noticeText": "F1KBNa_noticeText"
|
|
11754
11794
|
};
|
|
11755
11795
|
//#endregion
|
|
11756
11796
|
//#region lib/types/client/PendingPanel.js
|
|
@@ -11782,8 +11822,144 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11782
11822
|
/** File-list pane width bounds for the manual split drag, in px. */
|
|
11783
11823
|
const MIN_LIST_WIDTH_PX = 160;
|
|
11784
11824
|
const MAX_LIST_WIDTH_PX = 560;
|
|
11825
|
+
/** Inset of the floating file-list card from the code scroll box, in px. */
|
|
11826
|
+
const FLOAT_LIST_MARGIN_PX = 12;
|
|
11785
11827
|
/** Fixed diff-row height in px; the virtual window and jump math are built on it. */
|
|
11786
11828
|
const ROW_HEIGHT_PX = 22;
|
|
11829
|
+
/** Total width of the two line-number gutters, subtracted from the code width
|
|
11830
|
+
* when measuring wrapped line heights. */
|
|
11831
|
+
const WRAP_GUTTERS_PX = 88;
|
|
11832
|
+
/** A shared canvas for measuring wrapped line heights (CPU-only, no DOM reflow). */
|
|
11833
|
+
let measureCanvas;
|
|
11834
|
+
/**
|
|
11835
|
+
* Compute a diff line's visual sub-lines for soft wrap the way VSCode does it:
|
|
11836
|
+
* a Unicode line-break model — break at whitespace and between any two CJK
|
|
11837
|
+
* characters (Chinese han, Japanese kana, fullwidth forms), keep Latin and
|
|
11838
|
+
* numeric words atomic (a word longer than a whole line falls back to a
|
|
11839
|
+
* character split), and honor East Asian kinsoku so an opening bracket never
|
|
11840
|
+
* ends a line and a closing/terminal punctuation never starts one. Tabs
|
|
11841
|
+
* advance to the tab stop derived from the computed `tab-size`. This *is* the
|
|
11842
|
+
* wrap decision — the caller renders the returned sub-lines itself (never
|
|
11843
|
+
* `white-space: pre-wrap`), so the row height equals `subLines.length * 22`
|
|
11844
|
+
* by construction and can never drift from the browser re-wrapping.
|
|
11845
|
+
* The concatenation equals the input (no characters are dropped), so
|
|
11846
|
+
* highlight runs can be clipped back onto sub-lines by character offset.
|
|
11847
|
+
* @param text - the line's content (no trailing newline).
|
|
11848
|
+
* @param widthPx - the available code width, in px.
|
|
11849
|
+
* @param measure - `ctx.measureText` bound to the code font.
|
|
11850
|
+
* @param tabPx - the width of one tab stop, in px.
|
|
11851
|
+
*/
|
|
11852
|
+
const cpOf = (c) => c.codePointAt(0) ?? 0;
|
|
11853
|
+
/** Space, tab, or the ideographic space — whitespace is a break opportunity. */
|
|
11854
|
+
function isSpaceCode(cp) {
|
|
11855
|
+
return cp === 32 || cp === 9 || cp === 12288;
|
|
11856
|
+
}
|
|
11857
|
+
/**
|
|
11858
|
+
* CJK characters — Chinese han, Japanese kana, CJK fullwidth forms. Each is an
|
|
11859
|
+
* independent break opportunity (wrap between any two), unlike Latin words.
|
|
11860
|
+
*/
|
|
11861
|
+
function isCJKCode(cp) {
|
|
11862
|
+
return cp >= 12352 && cp <= 12543 || cp >= 13312 && cp <= 19903 || cp >= 19968 && cp <= 40959 || cp >= 63744 && cp <= 64255 || cp >= 65072 && cp <= 65103 || cp >= 65280 && cp <= 65519 || cp >= 131072 && cp <= 195103;
|
|
11863
|
+
}
|
|
11864
|
+
/** Opening bracket/quote — kinsoku forbids ending a line right after it. */
|
|
11865
|
+
function isOpenPunctCode(cp) {
|
|
11866
|
+
return cp === 40 || cp === 91 || cp === 123 || cp === 12296 || cp === 12298 || cp === 12300 || cp === 12302 || cp === 12304 || cp === 12308 || cp === 12310 || cp === 12312 || cp === 65288 || cp === 65339 || cp === 65371 || cp === 8216 || cp === 8220;
|
|
11867
|
+
}
|
|
11868
|
+
/** Closing bracket/quote or terminal punctuation — kinsoku forbids starting a line with it. */
|
|
11869
|
+
function isClosePunctCode(cp) {
|
|
11870
|
+
return cp === 41 || cp === 93 || cp === 125 || cp === 12289 || cp === 12290 || cp === 12297 || cp === 12299 || cp === 12301 || cp === 12303 || cp === 12305 || cp === 12309 || cp === 12311 || cp === 12313 || cp === 65289 || cp === 65341 || cp === 65373 || cp === 65292 || cp === 65294 || cp === 65281 || cp === 65311 || cp === 65307 || cp === 65306 || cp === 8217 || cp === 8221 || cp === 8230 || cp === 8212;
|
|
11871
|
+
}
|
|
11872
|
+
/**
|
|
11873
|
+
* Whether a line break is allowed between characters `a` (ending the current
|
|
11874
|
+
* line) and `b` (starting the next). Whitespace and any CJK/serial-boundary
|
|
11875
|
+
* admit a break; a full Latin/numeric word does not. Kinsoku forbids a break
|
|
11876
|
+
* after an opening punct or before a closing/terminal one.
|
|
11877
|
+
*/
|
|
11878
|
+
function breakValid(a, b) {
|
|
11879
|
+
const ac = cpOf(a);
|
|
11880
|
+
const bc = cpOf(b);
|
|
11881
|
+
if (isOpenPunctCode(ac)) return false;
|
|
11882
|
+
if (isClosePunctCode(bc)) return false;
|
|
11883
|
+
if (isSpaceCode(ac)) return true;
|
|
11884
|
+
if (isSpaceCode(bc)) return false;
|
|
11885
|
+
if (isCJKCode(ac) || isCJKCode(bc)) return true;
|
|
11886
|
+
return false;
|
|
11887
|
+
}
|
|
11888
|
+
/**
|
|
11889
|
+
* The largest index in `chars` at which a break may occur so the next line can
|
|
11890
|
+
* begin there with the overflowing character `next` (the break may be at the
|
|
11891
|
+
* line's end, `chars.length`). -1 when no position admits a break.
|
|
11892
|
+
*/
|
|
11893
|
+
function lastBreakIndex(chars, next) {
|
|
11894
|
+
for (let k = chars.length; k >= 1; k--) {
|
|
11895
|
+
const a = chars[k - 1];
|
|
11896
|
+
if (breakValid(a, k < chars.length ? chars[k] : next)) return k;
|
|
11897
|
+
}
|
|
11898
|
+
return -1;
|
|
11899
|
+
}
|
|
11900
|
+
/** Width of a code-point array, advancing tabs to the next stop. */
|
|
11901
|
+
function charsWidth(chars, measure, tabPx) {
|
|
11902
|
+
let w = 0;
|
|
11903
|
+
for (const c of chars) if (c === " ") w += tabPx - w % tabPx;
|
|
11904
|
+
else w += measure(c);
|
|
11905
|
+
return w;
|
|
11906
|
+
}
|
|
11907
|
+
function wrapInto(text, widthPx, measure, tabPx) {
|
|
11908
|
+
if (widthPx <= 0) return [text];
|
|
11909
|
+
const codepoints = Array.from(text);
|
|
11910
|
+
if (codepoints.length === 0) return [""];
|
|
11911
|
+
const out = [];
|
|
11912
|
+
let line = [];
|
|
11913
|
+
let lineW = 0;
|
|
11914
|
+
for (const ch of codepoints) {
|
|
11915
|
+
const adv = ch === " " ? tabPx - lineW % tabPx : measure(ch);
|
|
11916
|
+
if (line.length > 0 && lineW + adv > widthPx) {
|
|
11917
|
+
if (isSpaceCode(cpOf(ch))) {
|
|
11918
|
+
line.push(ch);
|
|
11919
|
+
lineW += adv;
|
|
11920
|
+
out.push(line.join(""));
|
|
11921
|
+
line = [];
|
|
11922
|
+
lineW = 0;
|
|
11923
|
+
continue;
|
|
11924
|
+
}
|
|
11925
|
+
const k = lastBreakIndex(line, ch);
|
|
11926
|
+
if (k >= 1) {
|
|
11927
|
+
out.push(line.slice(0, k).join(""));
|
|
11928
|
+
line = line.slice(k);
|
|
11929
|
+
lineW = charsWidth(line, measure, tabPx);
|
|
11930
|
+
} else {
|
|
11931
|
+
out.push(line.join(""));
|
|
11932
|
+
line = [];
|
|
11933
|
+
lineW = 0;
|
|
11934
|
+
}
|
|
11935
|
+
}
|
|
11936
|
+
line.push(ch);
|
|
11937
|
+
lineW += ch === " " ? tabPx - lineW % tabPx : measure(ch);
|
|
11938
|
+
}
|
|
11939
|
+
out.push(line.join(""));
|
|
11940
|
+
if (out.length > 1 && out[out.length - 1] === "") out.pop();
|
|
11941
|
+
return out;
|
|
11942
|
+
}
|
|
11943
|
+
/** Resolve the code cell's computed font for canvas measurement. */
|
|
11944
|
+
function codeFontOf() {
|
|
11945
|
+
const code = document.querySelector("[data-diff-code]");
|
|
11946
|
+
if (code === null) return void 0;
|
|
11947
|
+
const computed = getComputedStyle(code);
|
|
11948
|
+
return computed.font || `${computed.fontStyle} ${computed.fontWeight} ${computed.fontSize} ${computed.fontFamily}`;
|
|
11949
|
+
}
|
|
11950
|
+
/** Create a measurer bound to `font`; falls back to a rough char estimate. */
|
|
11951
|
+
function makeMeasurer(font) {
|
|
11952
|
+
if (typeof document === "undefined") return void 0;
|
|
11953
|
+
try {
|
|
11954
|
+
if (measureCanvas === void 0) measureCanvas = document.createElement("canvas").getContext("2d") ?? void 0;
|
|
11955
|
+
} catch {
|
|
11956
|
+
return;
|
|
11957
|
+
}
|
|
11958
|
+
const ctx = measureCanvas;
|
|
11959
|
+
if (ctx === void 0) return void 0;
|
|
11960
|
+
if (font !== void 0) ctx.font = font;
|
|
11961
|
+
return (text) => ctx.measureText(text).width;
|
|
11962
|
+
}
|
|
11787
11963
|
/** The overview ruler's width in px (mirrors `.overviewRuler`). The flash is
|
|
11788
11964
|
* kept off it even when the scroller has no vertical scrollbar. */
|
|
11789
11965
|
const OVERVIEW_RULER_WIDTH_PX = 4;
|
|
@@ -11799,6 +11975,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11799
11975
|
return index < 0 ? path : path.slice(index + 1);
|
|
11800
11976
|
}
|
|
11801
11977
|
/**
|
|
11978
|
+
* Order two paths by their displayed file name (dictionary, case-insensitive),
|
|
11979
|
+
* breaking a same-name tie on the full path so files in different directories
|
|
11980
|
+
* keep a stable order. The file list shows only the file name, so the panel
|
|
11981
|
+
* sorts by it here — the host's list order (oldest capture first) is not a
|
|
11982
|
+
* display guarantee.
|
|
11983
|
+
*/
|
|
11984
|
+
function compareFileNames(a, b) {
|
|
11985
|
+
const na = basenameOf(a).toLowerCase();
|
|
11986
|
+
const nb = basenameOf(b).toLowerCase();
|
|
11987
|
+
if (na !== nb) return na < nb ? -1 : 1;
|
|
11988
|
+
const pa = a.toLowerCase();
|
|
11989
|
+
const pb = b.toLowerCase();
|
|
11990
|
+
if (pa !== pb) return pa < pb ? -1 : 1;
|
|
11991
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
11992
|
+
}
|
|
11993
|
+
/**
|
|
11802
11994
|
* Open the DSH settings dialog and switch to this plugin's section. The
|
|
11803
11995
|
* settings shell keeps its open state and the active section id as
|
|
11804
11996
|
* component-local viewing state with no cross-plugin service, so the dialog
|
|
@@ -11824,18 +12016,56 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11824
12016
|
/** Empty failure map reused as the snapshot's canonical absent value. */
|
|
11825
12017
|
const EMPTY_FAILED_MAP = /* @__PURE__ */ new Map();
|
|
11826
12018
|
/**
|
|
12019
|
+
* Clip highlight runs (which partition one whole line) to the character range
|
|
12020
|
+
* `[start, end)` of that line, producing the sub-line's highlighted content.
|
|
12021
|
+
*/
|
|
12022
|
+
function clipRuns(runs, start, end) {
|
|
12023
|
+
const nodes = [];
|
|
12024
|
+
let pos = 0;
|
|
12025
|
+
for (const run of runs) {
|
|
12026
|
+
const runStart = pos;
|
|
12027
|
+
const runEnd = pos + run.text.length;
|
|
12028
|
+
pos = runEnd;
|
|
12029
|
+
if (runEnd <= start || runStart >= end) continue;
|
|
12030
|
+
const text = run.text.slice(Math.max(runStart, start) - runStart, Math.min(runEnd, end) - runStart);
|
|
12031
|
+
if (text.length === 0) continue;
|
|
12032
|
+
nodes.push((0, react_jsx_runtime.jsx)("span", {
|
|
12033
|
+
style: run.style,
|
|
12034
|
+
children: text
|
|
12035
|
+
}, nodes.length));
|
|
12036
|
+
}
|
|
12037
|
+
return nodes.length === 0 ? "\xA0" : nodes;
|
|
12038
|
+
}
|
|
12039
|
+
/**
|
|
11827
12040
|
* One rendered diff row, memoized so a poll or an unrelated state change
|
|
11828
12041
|
* does not re-render rows whose content, highlight, and focus are unchanged.
|
|
12042
|
+
* With auto-wrap on, `wrappedLines` carries the row's visual sub-lines and the
|
|
12043
|
+
* code cell renders each at a fixed 22px (never `pre-wrap`), so the row height
|
|
12044
|
+
* is `wrappedLines.length * 22` by construction.
|
|
11829
12045
|
*/
|
|
11830
12046
|
const DiffRow = (0, react.memo)(function DiffRow(props) {
|
|
11831
|
-
const { index, row, runs, focused, searchHit, searchCurrent, onRowHover } = props;
|
|
12047
|
+
const { index, row, runs, focused, searchHit, searchCurrent, onRowHover, wrappedLines } = props;
|
|
11832
12048
|
const lineNumber = row.kind === "del" ? row.oldLine : row.newLine;
|
|
11833
12049
|
const sideRuns = row.kind === "del" ? runs?.oldRuns : runs?.newRuns;
|
|
11834
12050
|
const lineRuns = lineNumber === void 0 ? void 0 : sideRuns?.[lineNumber - 1];
|
|
11835
|
-
|
|
12051
|
+
let code;
|
|
12052
|
+
if (wrappedLines === void 0) code = lineRuns !== void 0 && lineRuns.length > 0 ? lineRuns.map((span, spanIndex) => (0, react_jsx_runtime.jsx)("span", {
|
|
11836
12053
|
style: span.style,
|
|
11837
12054
|
children: span.text
|
|
11838
|
-
}, spanIndex));
|
|
12055
|
+
}, spanIndex)) : row.text === "" ? "\xA0" : row.text;
|
|
12056
|
+
else {
|
|
12057
|
+
const highlighted = lineRuns !== void 0 && lineRuns.length > 0;
|
|
12058
|
+
let offset = 0;
|
|
12059
|
+
code = wrappedLines.map((line, lineIndex) => {
|
|
12060
|
+
const start = offset;
|
|
12061
|
+
offset += line.length;
|
|
12062
|
+
const content = highlighted ? clipRuns(lineRuns, start, offset) : line === "" ? "\xA0" : line;
|
|
12063
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
12064
|
+
className: PendingPanel_module_css_default.subline,
|
|
12065
|
+
children: content
|
|
12066
|
+
}, lineIndex);
|
|
12067
|
+
});
|
|
12068
|
+
}
|
|
11839
12069
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
11840
12070
|
className: `${PendingPanel_module_css_default.line} ${ROW_CLASS[row.kind]}`,
|
|
11841
12071
|
"data-diff-line": row.kind,
|
|
@@ -11857,7 +12087,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11857
12087
|
(0, react_jsx_runtime.jsx)("span", {
|
|
11858
12088
|
className: PendingPanel_module_css_default.code,
|
|
11859
12089
|
"data-diff-code": true,
|
|
11860
|
-
children:
|
|
12090
|
+
children: code
|
|
11861
12091
|
})
|
|
11862
12092
|
]
|
|
11863
12093
|
});
|
|
@@ -12034,7 +12264,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12034
12264
|
});
|
|
12035
12265
|
}
|
|
12036
12266
|
/** The selected file's diff, actions, jump controls, and copy toolbar. */
|
|
12037
|
-
function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, failedMessage, onPasteReference, t, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen }) {
|
|
12267
|
+
function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, failedMessage, onPasteReference, t, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, floatMode, floatOpen, onToggleFileList }) {
|
|
12038
12268
|
const [langOverride, setLangOverride] = (0, react.useState)(void 0);
|
|
12039
12269
|
const [langMenuOpen, setLangMenuOpen] = (0, react.useState)(false);
|
|
12040
12270
|
const langMenuItems = (0, react.useMemo)(() => [{
|
|
@@ -12047,6 +12277,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12047
12277
|
const detectedLang = (0, react.useMemo)(() => langFromPath(file.path), [file.path]);
|
|
12048
12278
|
const lang = (0, react.useMemo)(() => langOverride ?? detectedLang, [detectedLang, langOverride]);
|
|
12049
12279
|
const langLabel = langOverride === void 0 ? detectedLang === void 0 ? t("action.langAuto") : t("action.langAutoDetected", { lang: languageDisplayName(detectedLang) }) : languageDisplayName(langOverride);
|
|
12280
|
+
const wrapKey = lang ?? "";
|
|
12281
|
+
const [langWrap, setLangWrap] = (0, react.useState)(() => wrapEnabled(wrapKey));
|
|
12282
|
+
(0, react.useEffect)(() => {
|
|
12283
|
+
setLangWrap(wrapEnabled(wrapKey));
|
|
12284
|
+
}, [wrapKey]);
|
|
12285
|
+
const toggleLangWrap = () => {
|
|
12286
|
+
const next = !langWrap;
|
|
12287
|
+
setLangWrap(next);
|
|
12288
|
+
setWrapEnabled(wrapKey, next);
|
|
12289
|
+
};
|
|
12290
|
+
const [tabWidthSpaces] = (0, react.useState)(() => tabWidth());
|
|
12050
12291
|
const model = (0, react.useMemo)(() => {
|
|
12051
12292
|
const diff = computeWholeFileDiff(file.oldText, file.newText);
|
|
12052
12293
|
return {
|
|
@@ -12112,6 +12353,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12112
12353
|
const [scrollTick, setScrollTick] = (0, react.useState)(0);
|
|
12113
12354
|
const [scrollTop, setScrollTop] = (0, react.useState)(0);
|
|
12114
12355
|
const [viewportHeight, setViewportHeight] = (0, react.useState)(0);
|
|
12356
|
+
const [bodyWidth, setBodyWidth] = (0, react.useState)(0);
|
|
12357
|
+
const [hScrollbarPx, setHScrollbarPx] = (0, react.useState)(0);
|
|
12115
12358
|
const [hoveredBlock, setHoveredBlock] = (0, react.useState)(void 0);
|
|
12116
12359
|
const [selection, setSelection] = (0, react.useState)(void 0);
|
|
12117
12360
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
@@ -12178,7 +12421,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12178
12421
|
if (row === void 0) return;
|
|
12179
12422
|
const body = bodyRef.current;
|
|
12180
12423
|
if (body === null) return;
|
|
12181
|
-
const target = row
|
|
12424
|
+
const target = offsetOf(row) + extentOf(row, row) / 2 - body.clientHeight / 2;
|
|
12182
12425
|
const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
|
|
12183
12426
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
12184
12427
|
setScrollTop(clamped);
|
|
@@ -12195,12 +12438,58 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12195
12438
|
}, [blockIndexByRow]);
|
|
12196
12439
|
const rows = model.diff.rows;
|
|
12197
12440
|
const rowCount = rows.length;
|
|
12198
|
-
const
|
|
12199
|
-
|
|
12200
|
-
|
|
12441
|
+
const rowWrapped = (0, react.useMemo)(() => {
|
|
12442
|
+
if (!langWrap || bodyWidth === 0) return null;
|
|
12443
|
+
const measure = makeMeasurer(codeFontOf());
|
|
12444
|
+
if (measure === void 0) return null;
|
|
12445
|
+
const charWidth = measure("0");
|
|
12446
|
+
const wrapping = bodyWidth - WRAP_GUTTERS_PX - charWidth;
|
|
12447
|
+
const tabPx = tabWidthSpaces * measure(" ");
|
|
12448
|
+
return rows.map((row) => wrapInto(row.text, wrapping, measure, tabPx));
|
|
12449
|
+
}, [
|
|
12450
|
+
langWrap,
|
|
12451
|
+
bodyWidth,
|
|
12452
|
+
rows,
|
|
12453
|
+
tabWidthSpaces
|
|
12454
|
+
]);
|
|
12455
|
+
const rowHeights = (0, react.useMemo)(() => {
|
|
12456
|
+
if (rowWrapped === null) return null;
|
|
12457
|
+
return rowWrapped.map((lines) => lines.length * ROW_HEIGHT_PX);
|
|
12458
|
+
}, [rowWrapped]);
|
|
12459
|
+
const rowOffsets = (0, react.useMemo)(() => {
|
|
12460
|
+
if (rowHeights === null) return null;
|
|
12461
|
+
const offs = new Array(rowHeights.length + 1);
|
|
12462
|
+
offs[0] = 0;
|
|
12463
|
+
for (let i = 0; i < rowHeights.length; i++) offs[i + 1] = offs[i] + rowHeights[i];
|
|
12464
|
+
return offs;
|
|
12465
|
+
}, [rowHeights]);
|
|
12466
|
+
const totalHeight = rowOffsets === null ? rowCount * ROW_HEIGHT_PX : rowOffsets[rowCount] ?? 0;
|
|
12467
|
+
const offsetOf = (index) => {
|
|
12468
|
+
if (rowOffsets === null) return index * ROW_HEIGHT_PX;
|
|
12469
|
+
return rowOffsets[Math.max(0, Math.min(index, rowCount))] ?? 0;
|
|
12470
|
+
};
|
|
12471
|
+
const extentOf = (from, to) => {
|
|
12472
|
+
if (rowOffsets === null) return (to - from + 1) * ROW_HEIGHT_PX;
|
|
12473
|
+
return Math.max(0, offsetOf(to + 1) - offsetOf(from));
|
|
12474
|
+
};
|
|
12475
|
+
const rowAtY = (y) => {
|
|
12476
|
+
if (rowOffsets === null) return Math.floor(y / ROW_HEIGHT_PX);
|
|
12477
|
+
if (y <= 0) return 0;
|
|
12478
|
+
let lo = 0;
|
|
12479
|
+
let hi = rowCount;
|
|
12480
|
+
while (lo < hi) {
|
|
12481
|
+
const mid = lo + hi + 1 >> 1;
|
|
12482
|
+
if (rowOffsets[mid] <= y) lo = mid;
|
|
12483
|
+
else hi = mid - 1;
|
|
12484
|
+
}
|
|
12485
|
+
return lo;
|
|
12486
|
+
};
|
|
12487
|
+
const viewport = viewportHeight > 0 ? viewportHeight : totalHeight;
|
|
12488
|
+
const start = Math.max(0, rowAtY(scrollTop) - OVERSCAN_ROWS);
|
|
12489
|
+
const end = Math.min(rowCount, rowAtY(scrollTop + viewport) + OVERSCAN_ROWS);
|
|
12201
12490
|
const visibleRows = rows.slice(start, end);
|
|
12202
|
-
const
|
|
12203
|
-
const
|
|
12491
|
+
const blockEnd = hoveredBlock === void 0 ? void 0 : model.blocks[hoveredBlock]?.end;
|
|
12492
|
+
const blockActionsTop = blockEnd === void 0 ? 0 : Math.min(offsetOf(blockEnd + 1), Math.max(0, totalHeight - BLOCK_ACTIONS_FRAME_PX));
|
|
12204
12493
|
const widestLine = (0, react.useMemo)(() => {
|
|
12205
12494
|
let widest = 0;
|
|
12206
12495
|
for (const row of model.diff.rows) if (row.text.length > widest) widest = row.text.length;
|
|
@@ -12219,13 +12508,27 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12219
12508
|
observer?.disconnect();
|
|
12220
12509
|
};
|
|
12221
12510
|
}, [file.id]);
|
|
12511
|
+
(0, react.useEffect)(() => {
|
|
12512
|
+
const body = bodyRef.current;
|
|
12513
|
+
if (body === null) return;
|
|
12514
|
+
const measure = () => {
|
|
12515
|
+
setBodyWidth(body.clientWidth);
|
|
12516
|
+
setHScrollbarPx(Math.max(0, body.offsetHeight - body.clientHeight));
|
|
12517
|
+
};
|
|
12518
|
+
measure();
|
|
12519
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
|
|
12520
|
+
observer?.observe(body);
|
|
12521
|
+
return () => {
|
|
12522
|
+
observer?.disconnect();
|
|
12523
|
+
};
|
|
12524
|
+
}, [file.id, langWrap]);
|
|
12222
12525
|
(0, react.useLayoutEffect)(() => {
|
|
12223
12526
|
if (rowCount === 0) return;
|
|
12224
12527
|
const block = model.blocks[focus];
|
|
12225
12528
|
if (block === void 0) return;
|
|
12226
12529
|
const body = bodyRef.current;
|
|
12227
12530
|
if (body === null) return;
|
|
12228
|
-
const target = block.start
|
|
12531
|
+
const target = offsetOf(block.start) - 44;
|
|
12229
12532
|
const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
|
|
12230
12533
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
12231
12534
|
setScrollTop(clamped);
|
|
@@ -12233,7 +12536,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12233
12536
|
model,
|
|
12234
12537
|
focus,
|
|
12235
12538
|
scrollTick,
|
|
12236
|
-
rowCount
|
|
12539
|
+
rowCount,
|
|
12540
|
+
rowOffsets === null
|
|
12237
12541
|
]);
|
|
12238
12542
|
const jump = (direction) => {
|
|
12239
12543
|
if (rowCount === 0) return;
|
|
@@ -12243,13 +12547,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12243
12547
|
for (let index = current + 1; index < model.blocks.length; index++) {
|
|
12244
12548
|
const block = model.blocks[index];
|
|
12245
12549
|
if (block === void 0) continue;
|
|
12246
|
-
if (block.start
|
|
12550
|
+
if (offsetOf(block.start) >= top) return index;
|
|
12247
12551
|
}
|
|
12248
12552
|
return 0;
|
|
12249
12553
|
});
|
|
12250
12554
|
setScrollTick((tick) => tick + 1);
|
|
12251
12555
|
setFlashKey((key) => key + 1);
|
|
12252
12556
|
};
|
|
12557
|
+
const stepBlock = (direction) => {
|
|
12558
|
+
const count = model.blocks.length;
|
|
12559
|
+
if (count === 0) return;
|
|
12560
|
+
const target = ((hoveredBlock ?? focus) + direction + count) % count;
|
|
12561
|
+
setHoveredBlock(target);
|
|
12562
|
+
setFocus(target);
|
|
12563
|
+
setScrollTick((tick) => tick + 1);
|
|
12564
|
+
setFlashKey((key) => key + 1);
|
|
12565
|
+
};
|
|
12253
12566
|
(0, react.useEffect)(() => {
|
|
12254
12567
|
if (jumpSignal === 0) return;
|
|
12255
12568
|
jump(1);
|
|
@@ -12339,6 +12652,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12339
12652
|
const scrollbarWidth = scroller.offsetWidth - scroller.clientWidth;
|
|
12340
12653
|
return Math.max(0, scroller.clientWidth - (scrollbarWidth > 0 ? 0 : OVERVIEW_RULER_WIDTH_PX));
|
|
12341
12654
|
})();
|
|
12655
|
+
const flashTop = focusedBlock === void 0 ? 0 : Math.max(0, offsetOf(focusedBlock.start) - scrollTop);
|
|
12656
|
+
const flashBottom = focusedBlock === void 0 ? 0 : Math.min(viewportHeight > 0 ? viewportHeight : Number.POSITIVE_INFINITY, offsetOf(focusedBlock.end + 1) - scrollTop);
|
|
12657
|
+
const flashHeight = Math.max(0, flashBottom - flashTop);
|
|
12342
12658
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
12343
12659
|
className: PendingPanel_module_css_default.diff,
|
|
12344
12660
|
"data-diff-approval-diff": true,
|
|
@@ -12385,6 +12701,19 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12385
12701
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
12386
12702
|
className: PendingPanel_module_css_default.diffActions,
|
|
12387
12703
|
children: [
|
|
12704
|
+
floatMode && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12705
|
+
label: t(floatOpen ? "action.hideFileList" : "action.showFileList"),
|
|
12706
|
+
side: "bottom",
|
|
12707
|
+
delayMs: 500,
|
|
12708
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
12709
|
+
type: "button",
|
|
12710
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
12711
|
+
"data-diff-file-list-toggle": true,
|
|
12712
|
+
"aria-label": t(floatOpen ? "action.hideFileList" : "action.showFileList"),
|
|
12713
|
+
onClick: onToggleFileList,
|
|
12714
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16, { size: 14 })
|
|
12715
|
+
})
|
|
12716
|
+
}),
|
|
12388
12717
|
(0, react_jsx_runtime.jsx)("span", {
|
|
12389
12718
|
className: PendingPanel_module_css_default.diffStats,
|
|
12390
12719
|
children: t("panel.stats", {
|
|
@@ -12483,14 +12812,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12483
12812
|
onMouseLeave: () => {
|
|
12484
12813
|
setHoveredBlock(void 0);
|
|
12485
12814
|
},
|
|
12815
|
+
style: { tabSize: tabWidthSpaces },
|
|
12486
12816
|
"data-diff-body": true,
|
|
12487
12817
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
12488
|
-
className: PendingPanel_module_css_default.lines
|
|
12489
|
-
style:
|
|
12818
|
+
className: `${PendingPanel_module_css_default.lines}${langWrap ? " " + PendingPanel_module_css_default.wrap : ""}`,
|
|
12819
|
+
style: langWrap ? {
|
|
12820
|
+
width: "100%",
|
|
12821
|
+
minWidth: "100%"
|
|
12822
|
+
} : { minWidth: `max(100%, ${widestLine}ch)` },
|
|
12490
12823
|
children: [
|
|
12491
12824
|
start > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
12492
12825
|
className: PendingPanel_module_css_default.vSpacer,
|
|
12493
|
-
style: { height: start
|
|
12826
|
+
style: { height: offsetOf(start) },
|
|
12494
12827
|
"aria-hidden": "true"
|
|
12495
12828
|
}),
|
|
12496
12829
|
visibleRows.map((row, offset) => {
|
|
@@ -12502,24 +12835,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12502
12835
|
focused: inFocusedBlock(index),
|
|
12503
12836
|
searchHit: searchHitSet.has(index),
|
|
12504
12837
|
searchCurrent: index === currentSearchRow,
|
|
12505
|
-
onRowHover
|
|
12838
|
+
onRowHover,
|
|
12839
|
+
wrappedLines: rowWrapped?.[index]
|
|
12506
12840
|
}, index);
|
|
12507
12841
|
}),
|
|
12508
12842
|
end < rowCount && (0, react_jsx_runtime.jsx)("div", {
|
|
12509
12843
|
className: PendingPanel_module_css_default.vSpacer,
|
|
12510
|
-
style: { height:
|
|
12511
|
-
"aria-hidden": "true"
|
|
12512
|
-
}),
|
|
12513
|
-
blockActionsPadPx > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
12514
|
-
className: PendingPanel_module_css_default.vSpacer,
|
|
12515
|
-
style: { height: blockActionsPadPx },
|
|
12844
|
+
style: { height: totalHeight - offsetOf(end) },
|
|
12516
12845
|
"aria-hidden": "true"
|
|
12517
12846
|
})
|
|
12518
12847
|
]
|
|
12519
12848
|
}), hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
12520
12849
|
className: PendingPanel_module_css_default.blockActions,
|
|
12521
12850
|
"data-diff-block-actions": true,
|
|
12522
|
-
style: { top:
|
|
12851
|
+
style: { top: blockActionsTop },
|
|
12523
12852
|
children: [
|
|
12524
12853
|
(0, react_jsx_runtime.jsx)("span", {
|
|
12525
12854
|
className: PendingPanel_module_css_default.blockPosition,
|
|
@@ -12529,6 +12858,28 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12529
12858
|
total: model.blocks.length
|
|
12530
12859
|
})
|
|
12531
12860
|
}),
|
|
12861
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
12862
|
+
type: "button",
|
|
12863
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
12864
|
+
"data-diff-block-prev": true,
|
|
12865
|
+
"aria-label": t("action.prevDiff"),
|
|
12866
|
+
disabled: busy,
|
|
12867
|
+
onClick: () => {
|
|
12868
|
+
stepBlock(-1);
|
|
12869
|
+
},
|
|
12870
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
|
|
12871
|
+
}),
|
|
12872
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
12873
|
+
type: "button",
|
|
12874
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
12875
|
+
"data-diff-block-next": true,
|
|
12876
|
+
"aria-label": t("action.nextDiff"),
|
|
12877
|
+
disabled: busy,
|
|
12878
|
+
onClick: () => {
|
|
12879
|
+
stepBlock(1);
|
|
12880
|
+
},
|
|
12881
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
12882
|
+
}),
|
|
12532
12883
|
(0, react_jsx_runtime.jsx)("button", {
|
|
12533
12884
|
type: "button",
|
|
12534
12885
|
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
@@ -12556,8 +12907,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12556
12907
|
className: PendingPanel_module_css_default.blockFlash,
|
|
12557
12908
|
"data-diff-block-flash": true,
|
|
12558
12909
|
style: {
|
|
12559
|
-
top:
|
|
12560
|
-
height:
|
|
12910
|
+
top: flashTop,
|
|
12911
|
+
height: flashHeight,
|
|
12561
12912
|
width: flashWidth
|
|
12562
12913
|
}
|
|
12563
12914
|
}, flashKey),
|
|
@@ -12622,6 +12973,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12622
12973
|
className: PendingPanel_module_css_default.overviewRuler,
|
|
12623
12974
|
"data-diff-approval-ruler": true,
|
|
12624
12975
|
"aria-hidden": "true",
|
|
12976
|
+
style: { bottom: hScrollbarPx },
|
|
12625
12977
|
children: rulerMarkers.map((marker, index) => (0, react_jsx_runtime.jsx)("div", {
|
|
12626
12978
|
className: `${PendingPanel_module_css_default.overviewMarker} ${marker.kind === "del" ? PendingPanel_module_css_default.markerDel : PendingPanel_module_css_default.markerAdd}`,
|
|
12627
12979
|
"data-diff-ruler-marker": marker.kind,
|
|
@@ -12687,6 +13039,23 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12687
13039
|
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 12 })]
|
|
12688
13040
|
})
|
|
12689
13041
|
})
|
|
13042
|
+
}),
|
|
13043
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
13044
|
+
label: langWrap ? t("action.toggleOff") : t("action.toggleOn"),
|
|
13045
|
+
side: "top",
|
|
13046
|
+
delayMs: 500,
|
|
13047
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
13048
|
+
type: "button",
|
|
13049
|
+
className: `${PendingPanel_module_css_default.langSelect}${langWrap ? " " + PendingPanel_module_css_default.wrapActive : ""}`,
|
|
13050
|
+
"data-diff-wrap": true,
|
|
13051
|
+
"aria-label": langWrap ? t("action.toggleOff") : t("action.toggleOn"),
|
|
13052
|
+
"aria-pressed": langWrap,
|
|
13053
|
+
onClick: toggleLangWrap,
|
|
13054
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
13055
|
+
className: PendingPanel_module_css_default.langLabel,
|
|
13056
|
+
children: t("action.wrap")
|
|
13057
|
+
})
|
|
13058
|
+
})
|
|
12690
13059
|
})
|
|
12691
13060
|
]
|
|
12692
13061
|
})
|
|
@@ -12731,6 +13100,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12731
13100
|
/** File-list pane width, adjustable by dragging the divider. */
|
|
12732
13101
|
const [listWidth, setListWidth] = (0, react.useState)(240);
|
|
12733
13102
|
const resizeDrag = (0, react.useRef)(null);
|
|
13103
|
+
/** Whether the floating (collapsed) file list is currently expanded. */
|
|
13104
|
+
const [floatOpen, setFloatOpen] = (0, react.useState)(false);
|
|
13105
|
+
/** The review panel's width, measured so the file list can collapse when it
|
|
13106
|
+
* would take more than a third of it (browser zoom / window resize). */
|
|
13107
|
+
const [panelWidth, setPanelWidth] = (0, react.useState)(0);
|
|
13108
|
+
const panelRef = (0, react.useRef)(null);
|
|
13109
|
+
const splitRef = (0, react.useRef)(null);
|
|
13110
|
+
/** The code scroll box's bounds within the split, so the floating card is
|
|
13111
|
+
* constrained to it. */
|
|
13112
|
+
const [floatBox, setFloatBox] = (0, react.useState)(null);
|
|
12734
13113
|
(0, react.useEffect)(() => {
|
|
12735
13114
|
onRefresh(current);
|
|
12736
13115
|
const timer = setInterval(() => {
|
|
@@ -12740,6 +13119,55 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12740
13119
|
clearInterval(timer);
|
|
12741
13120
|
};
|
|
12742
13121
|
}, [current, onRefresh]);
|
|
13122
|
+
(0, react.useEffect)(() => {
|
|
13123
|
+
const el = panelRef.current;
|
|
13124
|
+
if (el === null) return;
|
|
13125
|
+
const measure = () => {
|
|
13126
|
+
setPanelWidth(el.clientWidth);
|
|
13127
|
+
};
|
|
13128
|
+
measure();
|
|
13129
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
|
|
13130
|
+
observer?.observe(el);
|
|
13131
|
+
return () => {
|
|
13132
|
+
observer?.disconnect();
|
|
13133
|
+
};
|
|
13134
|
+
}, [open]);
|
|
13135
|
+
const floatMode = panelWidth > 0 && listWidth > panelWidth / 3;
|
|
13136
|
+
const toggleFileList = () => {
|
|
13137
|
+
setFloatOpen((value) => !value);
|
|
13138
|
+
};
|
|
13139
|
+
(0, react.useEffect)(() => {
|
|
13140
|
+
if (!floatMode || !floatOpen) return;
|
|
13141
|
+
const el = panelRef.current;
|
|
13142
|
+
if (el === null) return;
|
|
13143
|
+
const onPointerDown = (event) => {
|
|
13144
|
+
const target = event.target;
|
|
13145
|
+
if (target instanceof Element && (target.closest("[data-diff-floating-file-list]") !== null || target.closest("[data-diff-file-list-toggle]") !== null)) return;
|
|
13146
|
+
setFloatOpen(false);
|
|
13147
|
+
};
|
|
13148
|
+
el.addEventListener("pointerdown", onPointerDown, true);
|
|
13149
|
+
return () => {
|
|
13150
|
+
el.removeEventListener("pointerdown", onPointerDown, true);
|
|
13151
|
+
};
|
|
13152
|
+
}, [floatMode, floatOpen]);
|
|
13153
|
+
(0, react.useEffect)(() => {
|
|
13154
|
+
if (!floatMode || !floatOpen) return;
|
|
13155
|
+
const split = splitRef.current;
|
|
13156
|
+
const body = panelRef.current?.querySelector("[data-diff-body]");
|
|
13157
|
+
if (split === null || body == null) return;
|
|
13158
|
+
const s = split.getBoundingClientRect();
|
|
13159
|
+
const b = body.getBoundingClientRect();
|
|
13160
|
+
setFloatBox({
|
|
13161
|
+
left: b.left - s.left,
|
|
13162
|
+
top: b.top - s.top,
|
|
13163
|
+
width: b.width,
|
|
13164
|
+
height: b.height
|
|
13165
|
+
});
|
|
13166
|
+
}, [
|
|
13167
|
+
floatMode,
|
|
13168
|
+
floatOpen,
|
|
13169
|
+
panelWidth
|
|
13170
|
+
]);
|
|
12743
13171
|
(0, react.useEffect)(() => {
|
|
12744
13172
|
if (!open || !snapshot.redoCleared) return;
|
|
12745
13173
|
onAckRedoCleared();
|
|
@@ -12792,7 +13220,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12792
13220
|
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
12793
13221
|
};
|
|
12794
13222
|
}, [open]);
|
|
12795
|
-
const files = snapshot.files.filter((file) => file.sessionId === current);
|
|
13223
|
+
const files = snapshot.files.filter((file) => file.sessionId === current).sort((left, right) => compareFileNames(left.path, right.path));
|
|
12796
13224
|
/** Per-file keep/revert failures, surfaced inline on the row and detail. */
|
|
12797
13225
|
const failed = snapshot.failed ?? EMPTY_FAILED_MAP;
|
|
12798
13226
|
const failedInitialized = (0, react.useRef)(false);
|
|
@@ -12865,6 +13293,37 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12865
13293
|
}
|
|
12866
13294
|
}, entry.id);
|
|
12867
13295
|
const selectedFile = files.find((file) => file.id === selected);
|
|
13296
|
+
const fileListBody = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
13297
|
+
className: PendingPanel_module_css_default.listScroll,
|
|
13298
|
+
children: files.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
13299
|
+
className: PendingPanel_module_css_default.group,
|
|
13300
|
+
children: t("panel.group.current")
|
|
13301
|
+
}), (0, react_jsx_runtime.jsx)("ul", {
|
|
13302
|
+
className: PendingPanel_module_css_default.rows,
|
|
13303
|
+
children: files.map(renderEntry)
|
|
13304
|
+
})] })
|
|
13305
|
+
}), files.length > 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
13306
|
+
className: PendingPanel_module_css_default.bulkActions,
|
|
13307
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
13308
|
+
type: "button",
|
|
13309
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
13310
|
+
"data-diff-keep-all": true,
|
|
13311
|
+
disabled: bulkBusy !== null,
|
|
13312
|
+
onClick: () => {
|
|
13313
|
+
runBulk("keep");
|
|
13314
|
+
},
|
|
13315
|
+
children: bulkBusy === "keep" ? t("action.busy") : t("action.keepAll")
|
|
13316
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
13317
|
+
type: "button",
|
|
13318
|
+
className: PendingPanel_module_css_default.action,
|
|
13319
|
+
"data-diff-revert-all": true,
|
|
13320
|
+
disabled: bulkBusy !== null,
|
|
13321
|
+
onClick: () => {
|
|
13322
|
+
runBulk("revert");
|
|
13323
|
+
},
|
|
13324
|
+
children: bulkBusy === "revert" ? t("action.busy") : t("action.revertAll")
|
|
13325
|
+
})]
|
|
13326
|
+
})] });
|
|
12868
13327
|
const handleUndo = async (sessionId) => {
|
|
12869
13328
|
const id = await onUndo(sessionId);
|
|
12870
13329
|
if (id === void 0) return;
|
|
@@ -12948,6 +13407,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12948
13407
|
}),
|
|
12949
13408
|
open && (0, react_jsx_runtime.jsxs)("section", {
|
|
12950
13409
|
className: PendingPanel_module_css_default.panel,
|
|
13410
|
+
ref: panelRef,
|
|
12951
13411
|
style: { bottom: expanded ? PANEL_INSET_PX : bottomPx },
|
|
12952
13412
|
"data-diff-approval-panel": true,
|
|
12953
13413
|
"aria-label": t("panel.title"),
|
|
@@ -13046,44 +13506,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13046
13506
|
]
|
|
13047
13507
|
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
13048
13508
|
className: PendingPanel_module_css_default.split,
|
|
13509
|
+
ref: splitRef,
|
|
13049
13510
|
children: [
|
|
13050
|
-
(0, react_jsx_runtime.
|
|
13511
|
+
!floatMode && (0, react_jsx_runtime.jsx)("nav", {
|
|
13051
13512
|
className: PendingPanel_module_css_default.fileList,
|
|
13052
13513
|
style: { width: listWidth },
|
|
13053
13514
|
"data-diff-approval-file-list": true,
|
|
13054
|
-
children:
|
|
13055
|
-
className: PendingPanel_module_css_default.listScroll,
|
|
13056
|
-
children: files.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
13057
|
-
className: PendingPanel_module_css_default.group,
|
|
13058
|
-
children: t("panel.group.current")
|
|
13059
|
-
}), (0, react_jsx_runtime.jsx)("ul", {
|
|
13060
|
-
className: PendingPanel_module_css_default.rows,
|
|
13061
|
-
children: files.map(renderEntry)
|
|
13062
|
-
})] })
|
|
13063
|
-
}), files.length > 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
13064
|
-
className: PendingPanel_module_css_default.bulkActions,
|
|
13065
|
-
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
13066
|
-
type: "button",
|
|
13067
|
-
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
13068
|
-
"data-diff-keep-all": true,
|
|
13069
|
-
disabled: bulkBusy !== null,
|
|
13070
|
-
onClick: () => {
|
|
13071
|
-
runBulk("keep");
|
|
13072
|
-
},
|
|
13073
|
-
children: bulkBusy === "keep" ? t("action.busy") : t("action.keepAll")
|
|
13074
|
-
}), (0, react_jsx_runtime.jsx)("button", {
|
|
13075
|
-
type: "button",
|
|
13076
|
-
className: PendingPanel_module_css_default.action,
|
|
13077
|
-
"data-diff-revert-all": true,
|
|
13078
|
-
disabled: bulkBusy !== null,
|
|
13079
|
-
onClick: () => {
|
|
13080
|
-
runBulk("revert");
|
|
13081
|
-
},
|
|
13082
|
-
children: bulkBusy === "revert" ? t("action.busy") : t("action.revertAll")
|
|
13083
|
-
})]
|
|
13084
|
-
})]
|
|
13515
|
+
children: fileListBody
|
|
13085
13516
|
}),
|
|
13086
|
-
(0, react_jsx_runtime.jsx)("div", {
|
|
13517
|
+
!floatMode && (0, react_jsx_runtime.jsx)("div", {
|
|
13087
13518
|
className: PendingPanel_module_css_default.resizeHandle,
|
|
13088
13519
|
"data-diff-resize": true,
|
|
13089
13520
|
onMouseDown: startResize
|
|
@@ -13106,8 +13537,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13106
13537
|
onRevert,
|
|
13107
13538
|
onBlockKeep,
|
|
13108
13539
|
onBlockRevert,
|
|
13109
|
-
onOpen
|
|
13540
|
+
onOpen,
|
|
13541
|
+
floatMode,
|
|
13542
|
+
floatOpen,
|
|
13543
|
+
onToggleFileList: toggleFileList
|
|
13110
13544
|
})
|
|
13545
|
+
}),
|
|
13546
|
+
floatMode && floatOpen && files.length > 0 && floatBox !== null && (0, react_jsx_runtime.jsx)("div", {
|
|
13547
|
+
className: PendingPanel_module_css_default.fileListFloat,
|
|
13548
|
+
style: {
|
|
13549
|
+
left: floatBox.left + FLOAT_LIST_MARGIN_PX,
|
|
13550
|
+
top: floatBox.top + FLOAT_LIST_MARGIN_PX,
|
|
13551
|
+
width: Math.min(listWidth, Math.max(0, floatBox.width - 24)),
|
|
13552
|
+
height: Math.max(0, floatBox.height - 24)
|
|
13553
|
+
},
|
|
13554
|
+
"data-diff-floating-file-list": true,
|
|
13555
|
+
children: fileListBody
|
|
13111
13556
|
})
|
|
13112
13557
|
]
|
|
13113
13558
|
})]
|
|
@@ -13216,17 +13661,78 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13216
13661
|
})]
|
|
13217
13662
|
});
|
|
13218
13663
|
}
|
|
13664
|
+
/** A picker offering the tab-width choices 2 / 4 / 8 (spaces). */
|
|
13665
|
+
function TabWidthPicker({ value, open, onOpenChange, onSelect, dataAttribute }) {
|
|
13666
|
+
return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
13667
|
+
open,
|
|
13668
|
+
onClose: () => {
|
|
13669
|
+
onOpenChange(false);
|
|
13670
|
+
},
|
|
13671
|
+
items: [
|
|
13672
|
+
2,
|
|
13673
|
+
4,
|
|
13674
|
+
8
|
|
13675
|
+
].map((n) => ({
|
|
13676
|
+
id: String(n),
|
|
13677
|
+
label: String(n)
|
|
13678
|
+
})),
|
|
13679
|
+
selectedId: String(value),
|
|
13680
|
+
onSelect: (id) => {
|
|
13681
|
+
onOpenChange(false);
|
|
13682
|
+
const n = Number.parseInt(id, 10);
|
|
13683
|
+
if (Number.isFinite(n)) onSelect(n);
|
|
13684
|
+
},
|
|
13685
|
+
align: "end",
|
|
13686
|
+
portal: true,
|
|
13687
|
+
anchor: (0, react_jsx_runtime.jsxs)("button", {
|
|
13688
|
+
type: "button",
|
|
13689
|
+
className: PendingPanel_module_css_default.settingsSelector,
|
|
13690
|
+
"aria-haspopup": "menu",
|
|
13691
|
+
"aria-expanded": open,
|
|
13692
|
+
onClick: () => {
|
|
13693
|
+
onOpenChange(!open);
|
|
13694
|
+
},
|
|
13695
|
+
[dataAttribute]: true,
|
|
13696
|
+
children: [value, (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: PendingPanel_module_css_default.settingsSelectorChevron })]
|
|
13697
|
+
})
|
|
13698
|
+
});
|
|
13699
|
+
}
|
|
13700
|
+
/** One tab-width preference row: title + description, number picker right. */
|
|
13701
|
+
function TabWidthRow({ title, description, value, open, onOpenChange, onSelect, dataAttribute }) {
|
|
13702
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
13703
|
+
className: PendingPanel_module_css_default.settingsRow,
|
|
13704
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
13705
|
+
className: PendingPanel_module_css_default.settingsRowText,
|
|
13706
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
13707
|
+
className: PendingPanel_module_css_default.settingsRowTitle,
|
|
13708
|
+
children: title
|
|
13709
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
13710
|
+
className: PendingPanel_module_css_default.settingsRowDesc,
|
|
13711
|
+
children: description
|
|
13712
|
+
})]
|
|
13713
|
+
}), (0, react_jsx_runtime.jsx)(TabWidthPicker, {
|
|
13714
|
+
value,
|
|
13715
|
+
open,
|
|
13716
|
+
onOpenChange,
|
|
13717
|
+
onSelect,
|
|
13718
|
+
dataAttribute
|
|
13719
|
+
})]
|
|
13720
|
+
});
|
|
13721
|
+
}
|
|
13219
13722
|
/**
|
|
13220
|
-
* The plugin's preferences: auto-paste a copied reference into the input,
|
|
13221
|
-
* whether importing workspace VCS changes includes untracked files
|
|
13222
|
-
* mirrors the harness's Agent-preset row (title +
|
|
13223
|
-
* pill picker on the right)
|
|
13723
|
+
* The plugin's preferences: auto-paste a copied reference into the input,
|
|
13724
|
+
* whether importing workspace VCS changes includes untracked files, and the
|
|
13725
|
+
* diff's tab width. Each row mirrors the harness's Agent-preset row (title +
|
|
13726
|
+
* description on the left, a pill picker on the right); the tab-width row
|
|
13727
|
+
* offers 2 / 4 / 8 spaces.
|
|
13224
13728
|
*/
|
|
13225
13729
|
function DiffApprovalSettingsTab({ t }) {
|
|
13226
13730
|
const [pasteOnCopy, setPasteOnCopyState] = (0, react.useState)(pasteOnCopyEnabled);
|
|
13227
13731
|
const [pasteOnCopyOpen, setPasteOnCopyOpen] = (0, react.useState)(false);
|
|
13228
13732
|
const [includeUntracked, setIncludeUntrackedState] = (0, react.useState)(includeUntrackedEnabled);
|
|
13229
13733
|
const [includeUntrackedOpen, setIncludeUntrackedOpen] = (0, react.useState)(false);
|
|
13734
|
+
const [tab, setTabState] = (0, react.useState)(tabWidth);
|
|
13735
|
+
const [tabOpen, setTabOpen] = (0, react.useState)(false);
|
|
13230
13736
|
const setPasteOnCopy = (value) => {
|
|
13231
13737
|
setPasteOnCopyState(value);
|
|
13232
13738
|
setPasteOnCopyEnabled(value);
|
|
@@ -13235,28 +13741,44 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13235
13741
|
setIncludeUntrackedState(value);
|
|
13236
13742
|
setIncludeUntrackedEnabled(value);
|
|
13237
13743
|
};
|
|
13744
|
+
const setTab = (value) => {
|
|
13745
|
+
setTabState(value);
|
|
13746
|
+
setTabWidth(value);
|
|
13747
|
+
};
|
|
13238
13748
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
13239
13749
|
className: PendingPanel_module_css_default.settingsPage,
|
|
13240
13750
|
"data-diff-settings": true,
|
|
13241
|
-
children: [
|
|
13242
|
-
|
|
13243
|
-
|
|
13244
|
-
|
|
13245
|
-
|
|
13246
|
-
|
|
13247
|
-
|
|
13248
|
-
|
|
13249
|
-
|
|
13250
|
-
|
|
13251
|
-
|
|
13252
|
-
|
|
13253
|
-
|
|
13254
|
-
|
|
13255
|
-
|
|
13256
|
-
|
|
13257
|
-
|
|
13258
|
-
|
|
13259
|
-
|
|
13751
|
+
children: [
|
|
13752
|
+
(0, react_jsx_runtime.jsx)(PreferenceRow, {
|
|
13753
|
+
title: t("panel.pasteOnCopy"),
|
|
13754
|
+
description: t("panel.pasteOnCopyDesc"),
|
|
13755
|
+
value: pasteOnCopy,
|
|
13756
|
+
open: pasteOnCopyOpen,
|
|
13757
|
+
onOpenChange: setPasteOnCopyOpen,
|
|
13758
|
+
onSelect: setPasteOnCopy,
|
|
13759
|
+
dataAttribute: "data-diff-paste-on-copy-select",
|
|
13760
|
+
t
|
|
13761
|
+
}),
|
|
13762
|
+
(0, react_jsx_runtime.jsx)(PreferenceRow, {
|
|
13763
|
+
title: t("panel.importUntracked"),
|
|
13764
|
+
description: t("panel.importUntrackedDesc"),
|
|
13765
|
+
value: includeUntracked,
|
|
13766
|
+
open: includeUntrackedOpen,
|
|
13767
|
+
onOpenChange: setIncludeUntrackedOpen,
|
|
13768
|
+
onSelect: setIncludeUntracked,
|
|
13769
|
+
dataAttribute: "data-diff-import-untracked-select",
|
|
13770
|
+
t
|
|
13771
|
+
}),
|
|
13772
|
+
(0, react_jsx_runtime.jsx)(TabWidthRow, {
|
|
13773
|
+
title: t("panel.tabWidth"),
|
|
13774
|
+
description: t("panel.tabWidthDesc"),
|
|
13775
|
+
value: tab,
|
|
13776
|
+
open: tabOpen,
|
|
13777
|
+
onOpenChange: setTabOpen,
|
|
13778
|
+
onSelect: setTab,
|
|
13779
|
+
dataAttribute: "data-diff-tab-width-select"
|
|
13780
|
+
})
|
|
13781
|
+
]
|
|
13260
13782
|
});
|
|
13261
13783
|
}
|
|
13262
13784
|
//#endregion
|
|
@@ -13653,6 +14175,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13653
14175
|
"panel.pasteOnCopyDesc": "开启后,复制的引用会自动填入消息输入框,输入框会获得焦点。",
|
|
13654
14176
|
"panel.importUntracked": "导入未跟踪的文件改动",
|
|
13655
14177
|
"panel.importUntrackedDesc": "开启后,导入工作区改动会包含未跟踪/未版本化的新增文件(Git 未跟踪、SVN 未版本化、Perforce 未版本化)。收集改动需要扫描整个工作区,文件数量大时可能较慢。",
|
|
14178
|
+
"panel.tabWidth": "Tab 宽度",
|
|
14179
|
+
"panel.tabWidthDesc": "diff 中制表符(Tab)的缩进宽度,可选 2 / 4 / 8 个空格(默认 4),同时作用于行宽折行测量。",
|
|
13656
14180
|
"settings.tabLabel": "改动审批",
|
|
13657
14181
|
"row.create": "新增文件",
|
|
13658
14182
|
"row.failed": "失败",
|
|
@@ -13667,11 +14191,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13667
14191
|
"action.busy": "处理中…",
|
|
13668
14192
|
"action.prevDiff": "上一处差异",
|
|
13669
14193
|
"action.nextDiff": "下一处差异",
|
|
14194
|
+
"action.showFileList": "展开文件列表",
|
|
14195
|
+
"action.hideFileList": "收起文件列表",
|
|
13670
14196
|
"action.copyHint": "复制引用",
|
|
13671
14197
|
"action.copied": "已复制",
|
|
13672
14198
|
"action.langAuto": "自动",
|
|
13673
14199
|
"action.langAutoDetected": "自动:{lang}",
|
|
13674
14200
|
"action.langSelect": "高亮语言",
|
|
14201
|
+
"action.wrap": "自动换行",
|
|
13675
14202
|
"action.toggleOn": "打开",
|
|
13676
14203
|
"action.toggleOff": "关闭",
|
|
13677
14204
|
"action.importVcs": "导入工作区改动",
|
|
@@ -13711,6 +14238,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13711
14238
|
"panel.pasteOnCopyDesc": "When enabled, a copied reference is pasted into the composer, which then receives focus.",
|
|
13712
14239
|
"panel.importUntracked": "Import changes to untracked files",
|
|
13713
14240
|
"panel.importUntrackedDesc": "When enabled, importing workspace changes includes new/untracked files (Git-untracked, SVN-unversioned, Perforce-unversioned). Collecting changes scans the whole workspace, which can be slow on large trees.",
|
|
14241
|
+
"panel.tabWidth": "Tab width",
|
|
14242
|
+
"panel.tabWidthDesc": "The indent width of a tab character in the diff, as 2 / 4 / 8 spaces (default 4). Also drives the wrapped-line measurement.",
|
|
13714
14243
|
"settings.tabLabel": "Diff Approval",
|
|
13715
14244
|
"row.create": "New file",
|
|
13716
14245
|
"row.failed": "Failed",
|
|
@@ -13725,11 +14254,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13725
14254
|
"action.busy": "Working…",
|
|
13726
14255
|
"action.prevDiff": "Previous diff",
|
|
13727
14256
|
"action.nextDiff": "Next diff",
|
|
14257
|
+
"action.showFileList": "Show file list",
|
|
14258
|
+
"action.hideFileList": "Hide file list",
|
|
13728
14259
|
"action.copyHint": "Copy reference",
|
|
13729
14260
|
"action.copied": "Copied",
|
|
13730
14261
|
"action.langAuto": "Auto",
|
|
13731
14262
|
"action.langAutoDetected": "Auto: {lang}",
|
|
13732
14263
|
"action.langSelect": "Highlight language",
|
|
14264
|
+
"action.wrap": "Wrap lines",
|
|
13733
14265
|
"action.toggleOn": "On",
|
|
13734
14266
|
"action.toggleOff": "Off",
|
|
13735
14267
|
"action.importVcs": "Import workspace changes",
|
|
@@ -13758,10 +14290,64 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13758
14290
|
"sessions"
|
|
13759
14291
|
];
|
|
13760
14292
|
/**
|
|
14293
|
+
* The dsh web-react renderer gives `div[data-slot="sidebar.footer.action"]` an
|
|
14294
|
+
* inline `display: contents`, so every plugin's footer entry root participates
|
|
14295
|
+
* directly in the `.footerActions` flex row — several plugins (e.g. this one
|
|
14296
|
+
* plus a file-browser) get crammed into one row and a full-width badge
|
|
14297
|
+
* overflows. Stack the slot entries vertically instead (the same fix the
|
|
14298
|
+
* dsh-footer-order plugin injects), so each plugin gets its own row.
|
|
14299
|
+
*
|
|
14300
|
+
* We defer to the dedicated dsh-footer-order plugin when it is present, so the
|
|
14301
|
+
* two never fight.
|
|
14302
|
+
*
|
|
14303
|
+
* Why we detect it by its injected stylesheet's `--dsh-footer-order-gap` custom
|
|
14304
|
+
* property rather than by `ctx.slots.entriesOfSlot('settings.plugin.item')`
|
|
14305
|
+
* (where footer-order registers its settings card, id `footer-order`): that slot
|
|
14306
|
+
* key is not in our SlotMap type (would need a cast) and, more importantly, it
|
|
14307
|
+
* may not be an active slot in this dsh version at all — footer-order targets a
|
|
14308
|
+
* newer dsh settings API, so the detection could miss footer-order and we would
|
|
14309
|
+
* then both inject, fighting over the same `!important` rule. The CSS marker is
|
|
14310
|
+
* footer-order's own, and its presence is exactly "footer-order's rule is really
|
|
14311
|
+
* applied", which is what decides the layout. So only when the marker is absent
|
|
14312
|
+
* do we inject our own rule.
|
|
14313
|
+
*/
|
|
14314
|
+
function injectFooterStackStyle() {
|
|
14315
|
+
if (typeof document === "undefined") return;
|
|
14316
|
+
if (document.querySelector("style[data-diff-approval-footer-stack]") !== null) return;
|
|
14317
|
+
const CSS = "div[data-slot=\"sidebar.footer.action\"]{display:flex!important;flex-direction:column!important;flex:1 1 auto!important;align-items:stretch!important;}";
|
|
14318
|
+
const footerOrderInstalled = () => {
|
|
14319
|
+
for (const style of document.querySelectorAll("style")) if ((style.textContent ?? "").includes("--dsh-footer-order-gap")) return true;
|
|
14320
|
+
return false;
|
|
14321
|
+
};
|
|
14322
|
+
const inject = () => {
|
|
14323
|
+
if (document.querySelector("style[data-diff-approval-footer-stack]") !== null) return;
|
|
14324
|
+
if (footerOrderInstalled()) return;
|
|
14325
|
+
const style = document.createElement("style");
|
|
14326
|
+
style.setAttribute("data-diff-approval-footer-stack", "");
|
|
14327
|
+
style.textContent = CSS;
|
|
14328
|
+
document.head.appendChild(style);
|
|
14329
|
+
};
|
|
14330
|
+
if (document.querySelector("div[data-slot=\"sidebar.footer.action\"]") !== null) {
|
|
14331
|
+
inject();
|
|
14332
|
+
return;
|
|
14333
|
+
}
|
|
14334
|
+
const observer = new MutationObserver(() => {
|
|
14335
|
+
if (document.querySelector("div[data-slot=\"sidebar.footer.action\"]") !== null) {
|
|
14336
|
+
observer.disconnect();
|
|
14337
|
+
inject();
|
|
14338
|
+
}
|
|
14339
|
+
});
|
|
14340
|
+
observer.observe(document.documentElement, {
|
|
14341
|
+
childList: true,
|
|
14342
|
+
subtree: true
|
|
14343
|
+
});
|
|
14344
|
+
}
|
|
14345
|
+
/**
|
|
13761
14346
|
* Mount the pending-edit review panel.
|
|
13762
14347
|
* @param ctx - Client Cordis context carrying the wire and slot services.
|
|
13763
14348
|
*/
|
|
13764
14349
|
function apply(ctx) {
|
|
14350
|
+
injectFooterStackStyle();
|
|
13765
14351
|
ctx.effect(() => ctx.locale.register(NS, {
|
|
13766
14352
|
zh,
|
|
13767
14353
|
en
|