dsh-diff-approval 0.25.0 → 0.27.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/lib/client.js +2132 -639
- package/lib/index.js +68 -21
- package/lib/types/client/PendingPanel.d.ts +45 -0
- package/lib/types/client/discussion.d.ts +38 -1
- package/lib/types/client/dock.d.ts +10 -0
- package/lib/types/client/locales.d.ts +30 -4
- package/lib/types/client/panel-memory.d.ts +33 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -21,7 +21,7 @@ window.__ModuleLoader__.load({
|
|
|
21
21
|
let react_dom = require("react-dom");
|
|
22
22
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
23
23
|
//#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
|
|
24
|
-
const css = ".F1KBNa_panelFailure{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;gap:8px;padding:8px 10px;font-size:12px;line-height:16px;display:flex}.F1KBNa_panelFailureText{min-width:0}.F1KBNa_panelFailureRetry{border:1px solid var(--dsw-alias-border-l2);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:6px;flex:none;margin-left:auto;padding:2px 8px}.F1KBNa_panelFailureRetry:hover{background:var(--dsw-alias-interactive-bg-hover)}.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_headerEntry{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:28px;flex:none;justify-content:center;align-items:center;padding:6px;display:inline-flex;position:relative}.F1KBNa_headerEntry:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_headerEntry[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.F1KBNa_headerEntry:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_headerEntryCount{box-sizing:border-box;background:var(--dsw-alias-button-primary-fill);min-width:14px;height:14px;color:var(--dsw-alias-label-primary-foreground);text-align:center;font-variant-numeric:tabular-nums;pointer-events:none;border-radius:7px;padding:0 3px;font-size:10px;line-height:14px;position:absolute;top:-1px;right:-1px}.F1KBNa_headerEntry svg{display:block}.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_coverBackdrop{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);-webkit-user-select:none;user-select:none;border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_panel .F1KBNa_code,.F1KBNa_panel .F1KBNa_mdPreviewBody,.F1KBNa_panel .F1KBNa_discussionUser,.F1KBNa_panel .F1KBNa_discussionAnswer,.F1KBNa_panel .F1KBNa_quoteText,.F1KBNa_panel .F1KBNa_diffPath,.F1KBNa_panel .F1KBNa_rowPath,.F1KBNa_panel input,.F1KBNa_panel textarea,.F1KBNa_panel [contenteditable]{-webkit-user-select:text;user-select:text}.F1KBNa_panelDocked{width:100%;max-width:none;height:100%;box-shadow:none;border:none;border-radius:0;position:static;inset:auto}.F1KBNa_dockHost{flex-direction:column;min-height:0;display:flex;position:absolute;inset:0}.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_settingsGroup{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupHeader{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsGroupText{text-align:left;flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.F1KBNa_settingsGroupTitle{font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsGroupDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsGroupChevron{margin-left:auto;transition:transform .15s}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupChevron{transform:rotate(180deg)}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupHeader{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupBody{flex-direction:column;display:flex}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow{padding-left:16px}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow:last-child,.F1KBNa_settingsPage>.F1KBNa_settingsRow:last-child{border-bottom:none}.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);min-width:72px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelector[data-recording]{box-shadow:inset 0 0 0 1px var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-secondary)}.F1KBNa_settingsReset{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;margin-left:6px;padding:0;display:inline-flex}.F1KBNa_settingsReset:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_settingsReset:disabled{opacity:.4;cursor:default}.F1KBNa_colorPicker{position:relative}.F1KBNa_colorPickerTrigger{background:var(--dsw-alias-bg-module-platform);width:120px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_colorPickerTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_colorSwatch{border:1px solid var(--dsw-alias-border-l2);border-radius:50%;flex:none;width:24px;height:24px}.F1KBNa_colorValue{text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums;flex:1;min-width:0;overflow:hidden}.F1KBNa_colorPickerChevron{flex:none}.F1KBNa_colorBackdrop{z-index:40;position:fixed;inset:0}.F1KBNa_colorPickerPopover{z-index:41;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:10px;padding:10px;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_colorPickerPanel{flex-direction:column;gap:8px;display:flex}.F1KBNa_colorPickerInputRow{align-items:center;gap:8px;display:flex}.F1KBNa_colorPickerPreview{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;flex:none;width:22px;height:22px}.F1KBNa_colorPickerInput{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform);min-width:0;height:30px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 8px;font-size:12px;line-height:28px}.F1KBNa_colorPickerInput:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-1px}.F1KBNa_colorSv{border:1px solid var(--dsw-alias-border-l1);cursor:crosshair;touch-action:none;border-radius:8px;height:140px;position:relative}.F1KBNa_colorSvCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:14px;height:14px;position:absolute;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_colorHue{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;touch-action:none;border-radius:7px;height:14px;position:relative}.F1KBNa_colorHueCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:16px;height:16px;position:absolute;top:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_diffPreview{z-index:2;border:1px solid var(--dsw-alias-border-l1);font:var(--dsw-font-markdown-code-block);background:var(--dsw-alias-markdown-code-block);border-radius:8px;margin:16px 0 8px;padding:8px;position:sticky;top:0;overflow:hidden}.F1KBNa_diffPreviewTitle{color:var(--dsw-alias-label-tertiary);margin-bottom:6px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_diffPreviewScroll{overscroll-behavior:none;height:132px;overflow-y:auto}.F1KBNa_mdPreviewWrap{isolation:isolate;flex:1;min-width:0;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_mdPreviewBody{overscroll-behavior:none;min-width:0;min-height:0;color:var(--dsw-alias-label-primary);flex:1;padding:12px 16px;position:relative;overflow:auto}.F1KBNa_mdPreviewContent{width:100%;min-width:0;margin:0 auto}.F1KBNa_mdPreviewSingle{display:block}.F1KBNa_mdPreviewDouble{display:flex}.F1KBNa_mdPreviewBody .mdBlock{border-radius:4px;margin-bottom:12px;padding:2px 6px}.F1KBNa_mdPreviewBody .mdAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_mdPreviewBody .mdDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_mdPreviewBody .mdWordDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdWordAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdDouble{flex-direction:column;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleRow{align-items:flex-start;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleCol{flex:1;min-width:0}.F1KBNa_mdPreviewBody .mdDoubleRule{background:var(--dsw-alias-border-l2);flex:none;align-self:stretch;width:1px;margin:0 12px}.F1KBNa_mdPreviewFallback{font-family:var(--dsw-font-markdown-code-block);color:var(--dsw-alias-label-tertiary);padding:12px 16px;font-size:12px;line-height:18px}.F1KBNa_mdPreviewBody{word-break:break-word;font-size:13px;line-height:20px}.F1KBNa_mdPreviewBody>:first-child{margin-top:0}.F1KBNa_mdPreviewBody>:last-child{margin-bottom:0}.F1KBNa_mdPreviewBody h1,.F1KBNa_mdPreviewBody h2,.F1KBNa_mdPreviewBody h3,.F1KBNa_mdPreviewBody h4,.F1KBNa_mdPreviewBody h5,.F1KBNa_mdPreviewBody h6{margin:16px 0 8px;font-weight:600;line-height:1.3}.F1KBNa_mdPreviewBody h1{font-size:22px}.F1KBNa_mdPreviewBody h2{font-size:19px}.F1KBNa_mdPreviewBody h3{font-size:16px}.F1KBNa_mdPreviewBody h4{font-size:15px}.F1KBNa_mdPreviewBody h5{font-size:14px}.F1KBNa_mdPreviewBody h6{font-size:13px}.F1KBNa_mdPreviewBody p{margin:8px 0}.F1KBNa_mdPreviewBody ul,.F1KBNa_mdPreviewBody ol{margin:8px 0;padding-left:22px}.F1KBNa_mdPreviewBody li{margin:2px 0}.F1KBNa_mdPreviewBody a{color:var(--dsw-alias-state-business-primary);text-decoration:none}.F1KBNa_mdPreviewBody a:hover{text-decoration:underline}.F1KBNa_mdPreviewBody code{font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:4px;padding:1px 5px;font-size:12.5px}.F1KBNa_mdPreviewBody pre{overscroll-behavior:none;border:1px solid var(--dsw-alias-border-l1);font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:8px;margin:8px 0;padding:10px 12px;font-size:12.5px;line-height:18px;overflow:auto}.F1KBNa_mdPreviewBody pre code{background:0 0;padding:0}.F1KBNa_mdPreviewBody blockquote{border-left:3px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);margin:8px 0;padding:0 12px}.F1KBNa_mdPreviewBody hr{background:var(--dsw-alias-border-l1);border:none;height:1px;margin:16px 0}.F1KBNa_mdPreviewBody table{border-collapse:collapse;margin:8px 0}.F1KBNa_mdPreviewBody th,.F1KBNa_mdPreviewBody td{border:1px solid var(--dsw-alias-border-l1);padding:4px 10px}.F1KBNa_mdPreviewBody img{max-width:100%}.F1KBNa_mdPreviewBody .mdImageFallback{border:1px dashed var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-markdown-code-block) 45%, transparent);width:100%;min-height:120px;color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font-markdown-code-block);text-align:center;white-space:pre-wrap;word-break:break-all;border-radius:4px;justify-content:center;align-items:center;margin:0 auto;padding:8px 12px;font-size:12px;line-height:16px;display:flex}.F1KBNa_toggle{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:18px;flex:none;width:60px;height:36px;padding:0;position:relative}.F1KBNa_toggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_toggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.F1KBNa_toggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleOn:hover{background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleThumb{background:var(--dsw-alias-label-primary);border-radius:50%;width:28px;height:28px;transition:left .12s;position:absolute;top:3px;left:3px}.F1KBNa_toggleOn .F1KBNa_toggleThumb{background:#fff;left:27px}.F1KBNa_stepper{align-items:center;gap:6px;display:inline-flex}.F1KBNa_stepperButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);width:32px;height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:8px;padding:0;position:relative}.F1KBNa_stepperButton:before,.F1KBNa_stepperButton:after{content:\"\";background:currentColor;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_stepperButton:before{width:10px;height:1px}.F1KBNa_stepperButton:after{width:1px;height:10px;display:none}.F1KBNa_stepperButtonUp:after{display:block}.F1KBNa_stepperButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_stepperButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_stepperValue{text-align:center;min-width:2ch;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:14px;line-height:22px}.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_fileListKnob{z-index:39;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:28px;height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;box-shadow:var(--dsw-elevation-prominent);border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute}.F1KBNa_fileListKnob[data-open]{box-shadow:none;opacity:0}.F1KBNa_fileListKnob:not([data-open]){animation:.32s ease-in-out .5s both F1KBNa_fileListKnobIn}@keyframes F1KBNa_fileListKnobIn{0%{opacity:0}to{opacity:1}}.F1KBNa_fileListKnob:hover,.F1KBNa_fileListKnob:focus-visible{background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-interactive-bg-hover), var(--dsw-alias-interactive-bg-hover))}.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:none;transform-origin:0 0;border-radius:12px;flex-direction:column;padding:6px 0 10px 8px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileListFloatClosing{pointer-events:none;animation:.14s ease-in forwards F1KBNa_fileListShrink}@keyframes F1KBNa_fileListShrink{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.96)}}.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:scroll}.F1KBNa_bulkActions{flex:none;gap:6px;padding:8px 8px 0 0;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.F1KBNa_resizeHandle{cursor:col-resize;touch-action:none;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_floatResizeHandle{z-index:41;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;background:0 0;border-radius:4px;position:absolute}.F1KBNa_floatResizeHandle:hover{background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-border-l2), 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_confirmBackdrop{z-index:55;background:color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);justify-content:center;align-items:center;padding:24px;display:flex;position:absolute;inset:0}.F1KBNa_confirmCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:340px;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:12px;padding:16px;display:flex}.F1KBNa_confirmText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;line-height:1.5}.F1KBNa_confirmActions{flex:none;justify-content:flex-end;align-items:center;gap:8px;display:flex}.F1KBNa_pickerCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:420px;max-width:100%;height:70%;max-height:100%;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:8px;padding:14px 16px 16px;display:flex;position:relative;overflow:hidden}.F1KBNa_pickerTitle{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:20px}.F1KBNa_pickerClose{width:22px;height:22px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute;top:10px;right:10px}.F1KBNa_pickerClose:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_pickerForm{flex:none;gap:8px;display:flex}.F1KBNa_pickerInput{border:1px solid var(--dsw-alias-border-l1);min-width:0;color:var(--dsw-alias-label-primary);background:0 0;border-radius:8px;flex:auto;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_pickerInput:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.F1KBNa_tree{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex:auto;min-height:0;padding:4px 2px 4px 4px;overflow:auto scroll}.F1KBNa_treeRow{border-radius:6px;align-items:center;gap:2px;padding-right:4px;display:flex}.F1KBNa_treeRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_treeRow[data-selected]{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 18%, transparent)}.F1KBNa_treeCaret{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_treeCaret:hover{color:var(--dsw-alias-label-primary)}.F1KBNa_treeName{min-width:0;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:6px;flex:auto;align-items:center;gap:6px;padding:2px 4px;font-family:inherit;font-size:12px;line-height:18px;display:flex}.F1KBNa_treeName:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_treeNote{color:var(--dsw-alias-label-tertiary);margin:2px 0;font-size:12px;line-height:18px}.F1KBNa_pickerIcon{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_pickerName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_pickerNote{color:var(--dsw-alias-label-tertiary);flex:none;margin:0;font-size:12px;line-height:18px}.F1KBNa_pickerCheck{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;margin-right:auto;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_groupHead{align-items:center;gap:4px;margin:8px 0 4px;padding-right:8px;display:flex}.F1KBNa_action.F1KBNa_addButton{box-sizing:border-box;border-radius:6px;justify-content:center;align-items:center;width:20px;height:20px;min-height:0;padding:0;display:inline-flex}.F1KBNa_groupHead>.F1KBNa_group{margin:0}.F1KBNa_emptyActions{flex-wrap:wrap;justify-content:center;gap:8px;display:flex}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowMenuAnchor{display:none}.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:center;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;margin-left:4px;font-size:12px;line-height:18px;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(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsh-diff-del-color,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_panelDocked .F1KBNa_diffHeader{background:var(--dsw-alias-bg-base)}.F1KBNa_diffPath{appearance:none;min-width:0;font:inherit;text-overflow:ellipsis;color:var(--dsw-alias-label-primary);background:0 0;border:0;flex:1;margin-left:4px;padding:0;font-size:12px;line-height:18px;position:relative;top:1px}.F1KBNa_diffPath:focus{outline:none}.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_divider{background:var(--dsw-alias-border-l1);align-self:stretch;width:1px;margin:2px 0}.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_actionChord{color:var(--dsw-alias-label-tertiary);margin-left:6px;font-size:11px}.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{isolation:isolate;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffBody{overscroll-behavior:none;min-width:0;font:var(--dsw-font-markdown-code-block);-webkit-text-size-adjust:100%;text-size-adjust:100%;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_blockActionsDivider{background:var(--dsw-alias-border-l2);flex:none;align-self:stretch;width:1px;margin:2px 0}.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_searchToggle{border:1px solid var(--dsw-alias-border-l1);min-height:25px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;justify-content:center;align-items:center;padding:4px 6px;display:inline-flex}.F1KBNa_searchToggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_searchToggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchMatch{color:inherit;background-color:#facc1542;border-radius:2px}.F1KBNa_searchMatchCurrent{color:inherit;background-color:#facc1599;border-radius:2px}.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_diffFlashFade;position:absolute;left:0;right:0}.F1KBNa_blockFlashShake{animation:.7s ease-out forwards F1KBNa_diffFlashShake}.F1KBNa_discussionRow{background:var(--dsw-alias-bg-base);display:table-row}.F1KBNa_discussionCell{display:table-cell}.F1KBNa_discussionPin{width:0;height:0;position:sticky;left:0}.F1KBNa_discussion{z-index:2;box-sizing:border-box;border-left:3px solid var(--dsw-alias-label-secondary);cursor:default;background:0 0;flex-direction:column;display:flex;position:absolute;top:0;left:0;overflow:hidden}.F1KBNa_discussionHead,.F1KBNa_discussionBody{font:var(--dsw-font-markdown-code-block)}.F1KBNa_discussionBody{flex-direction:column;flex:auto;min-height:0;padding:0 12px;display:flex;overflow:hidden}.F1KBNa_discussion[data-lost]{border-left-color:var(--dsw-alias-state-warn-primary,#f59e0b);background:repeating-linear-gradient(135deg, var(--dsw-alias-interactive-bg-hover) 0 4px, transparent 4px 8px);background-origin:border-box}.F1KBNa_discussionAnswer{color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;margin:0;padding:0;font-family:inherit;line-height:22px}.F1KBNa_discussionUser{box-sizing:border-box;background:color-mix(in srgb, var(--dsw-specific-bubble,var(--dsw-alias-bg-layer-2,var(--dsw-alias-interactive-bg-hover))) 80%, transparent);width:fit-content;max-width:82%;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;border-radius:8px 0 8px 8px;margin:6.6px 0 6.6px auto;padding:4.4px 11px;font-family:inherit;line-height:22px}.F1KBNa_discussionCode{background:var(--dsw-alias-markdown-inline-code,var(--dsw-alias-interactive-bg-hover-solid));box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l1);border-radius:4px;padding:0 2px}.F1KBNa_discussionBody strong{-webkit-text-stroke:.3px currentColor;font-weight:700}.F1KBNa_discussionNote{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;padding:0;font-family:inherit;line-height:22px}.F1KBNa_discussionNote[data-diff-discussion-hidden]{color:var(--dsw-alias-label-tertiary)}.F1KBNa_discussionDots{margin-left:1px}.F1KBNa_discussionDots>span{animation:1.2s ease-in-out infinite F1KBNa_discussionDot}.F1KBNa_discussionDots>span:nth-child(2){animation-delay:.15s}.F1KBNa_discussionDots>span:nth-child(3){animation-delay:.3s}@keyframes F1KBNa_discussionDot{0%,60%,to{opacity:.25}30%{opacity:1}}.F1KBNa_quoteLines{table-layout:fixed;border-spacing:0;width:calc(100% + 27px);min-width:0;color:var(--dsw-alias-label-primary);font-size:calc(1em * var(--dsh-diff-font-scale,1));line-height:var(--dsh-diff-line-height,22px);background:color-mix(in srgb, var(--dsw-alias-interactive-bg-hover) 55%, transparent);margin:0 -12px 0 -15px;display:table}.F1KBNa_quoteAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 12%, transparent)}.F1KBNa_quoteDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 13%, transparent)}.F1KBNa_quoteLine{height:var(--dsh-diff-line-height,22px);display:table-row}.F1KBNa_quoteCode{display:table-cell}.F1KBNa_quoteText{white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;display:block}.F1KBNa_quoteNoWrap .F1KBNa_quoteText{white-space:pre;overflow-wrap:normal;overflow:hidden}.F1KBNa_quoteNoWrap .F1KBNa_quoteText:after{content:\"\";width:calc(var(--dsh-diff-quote-width,0px) + 100%);display:inline-block}.F1KBNa_discussionOutdated{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:16px}.F1KBNa_discussionHead{box-sizing:border-box;flex:none;align-items:center;gap:8px;height:22px;padding:0 12px;font-size:12px;line-height:16px;display:flex}.F1KBNa_discussionCompose{box-sizing:border-box;flex:none;align-items:flex-end;gap:8px;height:44px;margin:auto -6px 0;padding:0 0 6.6px;display:flex}.F1KBNa_discussionInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);min-width:0;color:var(--dsw-alias-label-primary);cursor:text;border-radius:6px;flex:auto;padding:3px 8px;font-family:inherit;line-height:18px}.F1KBNa_discussionToggle{width:18px;height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_discussionToggle:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_discussionRangeWrap{font:var(--dsw-font-markdown-code-block);flex:none}.F1KBNa_discussionRange{color:var(--dsw-alias-label-tertiary);font-family:inherit}.F1KBNa_discussionInput:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.F1KBNa_discussionInput::placeholder{font-family:inherit;font-size:inherit;color:var(--dsw-alias-label-tertiary)}.F1KBNa_discussionSend{box-sizing:border-box;white-space:nowrap;flex:none;justify-content:center;align-items:center;gap:6px;padding-left:9px;padding-right:9px;display:inline-flex}.F1KBNa_rowDiscussed{--diff-row-wash:color-mix(in srgb, var(--dsw-alias-label-secondary) 14%, transparent);background-image:linear-gradient(var(--diff-row-wash), var(--diff-row-wash))}@keyframes F1KBNa_diffFlashFade{0%{opacity:1}to{opacity:0}}@keyframes F1KBNa_diffFlashShake{0%{opacity:1;transform:translateY(0)}10%{transform:translateY(1px)}20%{transform:translateY(-1px)}30%{transform:translateY(1px)}40%{transform:translateY(-1px)}50%{transform:translateY(1px)}60%{transform:translateY(-1px)}70%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(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%;font-size:calc(1em * var(--dsh-diff-font-scale,1));display:table}.F1KBNa_line{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);-webkit-user-select:none;user-select:none;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;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_line>.F1KBNa_gutter{z-index:1;background-color:var(--dsw-alias-markdown-code-block);background-image:linear-gradient(var(--diff-row-tint,transparent), var(--diff-row-tint,transparent)), linear-gradient(var(--diff-row-wash,transparent), var(--diff-row-wash,transparent));position:sticky;left:0}.F1KBNa_line>.F1KBNa_gutter+.F1KBNa_gutter{left:44px}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{--diff-row-tint:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent);background-color:var(--diff-row-tint)}.F1KBNa_add{--diff-row-tint:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent);background-color:var(--diff-row-tint)}.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_presentationSelect{cursor:pointer;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_presentationSelect:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_chip{justify-content:flex-end;align-items:center;gap:5px;min-width:0;padding-right:14px;display:inline-flex}.F1KBNa_chipLabel{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_coverHost{align-items:center;display:inline-flex;position:relative}.F1KBNa_coverCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;align-items:center;gap:4px;padding:6px;display:flex}.F1KBNa_coverPopover{z-index:50;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_coverNotice{z-index:80;pointer-events:none;animation:1.25s ease-out forwards F1KBNa_coverNoticeFade;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_coverNoticeCard{gap:4px;padding:6px 8px}@keyframes F1KBNa_coverNoticeFade{0%,78%{opacity:1}to{opacity:0}}.F1KBNa_coverNoticeGlyph{width:44px;height:44px;color:var(--dsw-alias-label-tertiary);border-radius:10px;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_coverNoticeGlyph[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_coverNoticeGlyph[data-changed]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_coverNoticeText{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.F1KBNa_coverButton{width:32px;height:32px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_coverButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_coverButton[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_presentationHost{align-items:center;display:inline-flex}.F1KBNa_chipPresentation{min-width:36px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:20px;flex:none;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_chipPresentation:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_mirrored{transform:scaleX(-1)}.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:var(--dsh-diff-line-height,22px)}.F1KBNa_subline{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);white-space:pre;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))}.F1KBNa_splitRoot{isolation:isolate;flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;display:flex}.F1KBNa_splitCol{box-sizing:border-box;flex:1 1 0;min-width:0;overflow:hidden}.F1KBNa_splitDivider{background:var(--dsw-alias-border-l2);flex:0 0 1px}.F1KBNa_splitCol .F1KBNa_gutter,.F1KBNa_splitCol .F1KBNa_code{vertical-align:top}.F1KBNa_splitHScrollRow{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;width:100%;min-width:0;display:flex}.F1KBNa_splitHScroll{overscroll-behavior:none;min-width:0;height:var(--dsh-scrollbar-width,8px);flex:1 1 0;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:var(--dsh-scrollbar-width,8px)}.F1KBNa_splitHScroll::-webkit-scrollbar-track{cursor:default}.F1KBNa_splitHScroll::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_splitHScrollFill{height:1px}.F1KBNa_splitLdel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent)}.F1KBNa_intraDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 34%, transparent);text-decoration:line-through}.F1KBNa_intraAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 32%, transparent)}";
|
|
24
|
+
const css = ".F1KBNa_panelFailure{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;gap:8px;padding:8px 10px;font-size:12px;line-height:16px;display:flex}.F1KBNa_panelFailureText{min-width:0}.F1KBNa_panelFailureRetry{border:1px solid var(--dsw-alias-border-l2);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:6px;flex:none;margin-left:auto;padding:2px 8px}.F1KBNa_panelFailureRetry:hover{background:var(--dsw-alias-interactive-bg-hover)}.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_headerEntry{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:28px;flex:none;justify-content:center;align-items:center;padding:6px;display:inline-flex;position:relative}.F1KBNa_headerEntry:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_headerEntry[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.F1KBNa_headerEntry:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_headerEntryCount{box-sizing:border-box;background:var(--dsw-alias-button-primary-fill);min-width:14px;height:14px;color:var(--dsw-alias-label-primary-foreground);text-align:center;font-variant-numeric:tabular-nums;pointer-events:none;border-radius:7px;padding:0 3px;font-size:10px;line-height:14px;position:absolute;top:-1px;right:-1px}.F1KBNa_headerEntry svg{display:block}.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_coverBackdrop{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);-webkit-user-select:none;user-select:none;border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_panel .F1KBNa_code,.F1KBNa_panel .F1KBNa_mdPreviewBody,.F1KBNa_panel .F1KBNa_discussionUser,.F1KBNa_panel .F1KBNa_discussionAnswer,.F1KBNa_panel .F1KBNa_quoteText,.F1KBNa_panel .F1KBNa_diffPath,.F1KBNa_panel .F1KBNa_rowPath,.F1KBNa_panel input,.F1KBNa_panel textarea,.F1KBNa_panel [contenteditable]{-webkit-user-select:text;user-select:text}.F1KBNa_panelDocked{width:100%;max-width:none;height:100%;box-shadow:none;border:none;border-radius:0;position:static;inset:auto}.F1KBNa_dockHost{flex-direction:column;min-height:0;display:flex;position:absolute;inset:0}.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_settingsGroup{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupHeader{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsGroupText{text-align:left;flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.F1KBNa_settingsGroupTitle{font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsGroupDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsGroupChevron{margin-left:auto;transition:transform .15s}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupChevron{transform:rotate(180deg)}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupHeader{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupBody{flex-direction:column;display:flex}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow{padding-left:16px}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow:last-child,.F1KBNa_settingsPage>.F1KBNa_settingsRow:last-child{border-bottom:none}.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);min-width:72px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelector[data-recording]{box-shadow:inset 0 0 0 1px var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-secondary)}.F1KBNa_settingsReset{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;margin-left:6px;padding:0;display:inline-flex}.F1KBNa_settingsReset:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_settingsReset:disabled{opacity:.4;cursor:default}.F1KBNa_colorPicker{position:relative}.F1KBNa_colorPickerTrigger{background:var(--dsw-alias-bg-module-platform);width:120px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_colorPickerTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_colorSwatch{border:1px solid var(--dsw-alias-border-l2);border-radius:50%;flex:none;width:24px;height:24px}.F1KBNa_colorValue{text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums;flex:1;min-width:0;overflow:hidden}.F1KBNa_colorPickerChevron{flex:none}.F1KBNa_colorBackdrop{z-index:40;position:fixed;inset:0}.F1KBNa_colorPickerPopover{z-index:41;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:10px;padding:10px;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_colorPickerPanel{flex-direction:column;gap:8px;display:flex}.F1KBNa_colorPickerInputRow{align-items:center;gap:8px;display:flex}.F1KBNa_colorPickerPreview{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;flex:none;width:22px;height:22px}.F1KBNa_colorPickerInput{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform);min-width:0;height:30px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 8px;font-size:12px;line-height:28px}.F1KBNa_colorPickerInput:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-1px}.F1KBNa_colorSv{border:1px solid var(--dsw-alias-border-l1);cursor:crosshair;touch-action:none;border-radius:8px;height:140px;position:relative}.F1KBNa_colorSvCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:14px;height:14px;position:absolute;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_colorHue{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;touch-action:none;border-radius:7px;height:14px;position:relative}.F1KBNa_colorHueCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:16px;height:16px;position:absolute;top:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_diffPreview{z-index:2;border:1px solid var(--dsw-alias-border-l1);font:var(--dsw-font-markdown-code-block);background:var(--dsw-alias-markdown-code-block);border-radius:8px;margin:16px 0 8px;padding:8px;position:sticky;top:0;overflow:hidden}.F1KBNa_diffPreviewTitle{color:var(--dsw-alias-label-tertiary);margin-bottom:6px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_diffPreviewScroll{height:132px;overflow-y:auto}.F1KBNa_mdPreviewWrap{isolation:isolate;flex:1;min-width:0;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_mdPreviewBody{overscroll-behavior:none;min-width:0;min-height:0;color:var(--dsw-alias-label-primary);flex:1;padding:12px 16px;position:relative;overflow:auto}.F1KBNa_mdPreviewContent{width:100%;min-width:0;margin:0 auto}.F1KBNa_mdPreviewSingle{display:block}.F1KBNa_mdPreviewDouble{display:flex}.F1KBNa_mdPreviewBody .mdBlock{border-radius:4px;margin-bottom:12px;padding:2px 6px}.F1KBNa_mdPreviewBody .mdAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_mdPreviewBody .mdDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_mdPreviewBody .mdWordDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdWordAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdDouble{flex-direction:column;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleRow{align-items:flex-start;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleCol{flex:1;min-width:0}.F1KBNa_mdPreviewBody .mdDoubleRule{background:var(--dsw-alias-border-l2);flex:none;align-self:stretch;width:1px;margin:0 12px}.F1KBNa_mdPreviewFallback{font-family:var(--dsw-font-markdown-code-block);color:var(--dsw-alias-label-tertiary);padding:12px 16px;font-size:12px;line-height:18px}.F1KBNa_mdPreviewBody{word-break:break-word;font-size:13px;line-height:20px}.F1KBNa_mdPreviewBody>:first-child{margin-top:0}.F1KBNa_mdPreviewBody>:last-child{margin-bottom:0}.F1KBNa_mdPreviewBody h1,.F1KBNa_mdPreviewBody h2,.F1KBNa_mdPreviewBody h3,.F1KBNa_mdPreviewBody h4,.F1KBNa_mdPreviewBody h5,.F1KBNa_mdPreviewBody h6{margin:16px 0 8px;font-weight:600;line-height:1.3}.F1KBNa_mdPreviewBody h1{font-size:22px}.F1KBNa_mdPreviewBody h2{font-size:19px}.F1KBNa_mdPreviewBody h3{font-size:16px}.F1KBNa_mdPreviewBody h4{font-size:15px}.F1KBNa_mdPreviewBody h5{font-size:14px}.F1KBNa_mdPreviewBody h6{font-size:13px}.F1KBNa_mdPreviewBody p{margin:8px 0}.F1KBNa_mdPreviewBody ul,.F1KBNa_mdPreviewBody ol{margin:8px 0;padding-left:22px}.F1KBNa_mdPreviewBody li{margin:2px 0}.F1KBNa_mdPreviewBody a{color:var(--dsw-alias-state-business-primary);text-decoration:none}.F1KBNa_mdPreviewBody a:hover{text-decoration:underline}.F1KBNa_mdPreviewBody code{font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:4px;padding:1px 5px;font-size:12.5px}.F1KBNa_mdPreviewBody pre{overscroll-behavior-x:none;border:1px solid var(--dsw-alias-border-l1);font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:8px;margin:8px 0;padding:10px 12px;font-size:12.5px;line-height:18px;overflow:auto}.F1KBNa_mdPreviewBody pre code{background:0 0;padding:0}.F1KBNa_mdPreviewBody blockquote{border-left:3px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);margin:8px 0;padding:0 12px}.F1KBNa_mdPreviewBody hr{background:var(--dsw-alias-border-l1);border:none;height:1px;margin:16px 0}.F1KBNa_mdPreviewBody table{border-collapse:collapse;margin:8px 0}.F1KBNa_mdPreviewBody th,.F1KBNa_mdPreviewBody td{border:1px solid var(--dsw-alias-border-l1);padding:4px 10px}.F1KBNa_mdPreviewBody img{max-width:100%}.F1KBNa_mdPreviewBody .mdImageFallback{border:1px dashed var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-markdown-code-block) 45%, transparent);width:100%;min-height:120px;color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font-markdown-code-block);text-align:center;white-space:pre-wrap;word-break:break-all;border-radius:4px;justify-content:center;align-items:center;margin:0 auto;padding:8px 12px;font-size:12px;line-height:16px;display:flex}.F1KBNa_toggle{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:18px;flex:none;width:60px;height:36px;padding:0;position:relative}.F1KBNa_toggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_toggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.F1KBNa_toggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleOn:hover{background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleThumb{background:var(--dsw-alias-label-primary);border-radius:50%;width:28px;height:28px;transition:left .12s;position:absolute;top:3px;left:3px}.F1KBNa_toggleOn .F1KBNa_toggleThumb{background:#fff;left:27px}.F1KBNa_stepper{align-items:center;gap:6px;display:inline-flex}.F1KBNa_stepperButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);width:32px;height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:8px;padding:0;position:relative}.F1KBNa_stepperButton:before,.F1KBNa_stepperButton:after{content:\"\";background:currentColor;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_stepperButton:before{width:10px;height:1px}.F1KBNa_stepperButton:after{width:1px;height:10px;display:none}.F1KBNa_stepperButtonUp:after{display:block}.F1KBNa_stepperButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_stepperButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_stepperValue{text-align:center;min-width:2ch;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:14px;line-height:22px}.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_fileListKnob{z-index:39;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:28px;height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;box-shadow:var(--dsw-elevation-prominent);border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute}.F1KBNa_fileListKnob[data-open]{box-shadow:none;opacity:0}.F1KBNa_fileListKnob:not([data-open]){animation:.32s ease-in-out .5s both F1KBNa_fileListKnobIn}@keyframes F1KBNa_fileListKnobIn{0%{opacity:0}to{opacity:1}}.F1KBNa_fileListKnob:hover,.F1KBNa_fileListKnob:focus-visible{background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-interactive-bg-hover), var(--dsw-alias-interactive-bg-hover))}.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:none;transform-origin:0 0;border-radius:12px;flex-direction:column;padding:6px 0 10px 8px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileListFloatClosing{pointer-events:none;animation:.14s ease-in forwards F1KBNa_fileListShrink}@keyframes F1KBNa_fileListShrink{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.96)}}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:260px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:scroll}.F1KBNa_bulkActions{flex:none;gap:6px;padding:8px 8px 0 0;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:auto}.F1KBNa_addPath{justify-content:center;align-items:center;gap:4px;display:inline-flex}.F1KBNa_resizeHandle{cursor:col-resize;touch-action:none;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_floatResizeHandle{z-index:41;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;background:0 0;border-radius:4px;position:absolute}.F1KBNa_floatResizeHandle:hover{background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-border-l2), 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_confirmBackdrop{z-index:55;background:color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);justify-content:center;align-items:center;padding:24px;display:flex;position:absolute;inset:0}.F1KBNa_confirmCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:340px;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:12px;padding:16px;display:flex}.F1KBNa_confirmText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;line-height:1.5}.F1KBNa_confirmActions{flex:none;justify-content:flex-end;align-items:center;gap:8px;display:flex}.F1KBNa_pickerCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:420px;max-width:100%;height:70%;max-height:100%;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:8px;padding:14px 16px 16px;display:flex;position:relative;overflow:hidden}.F1KBNa_pickerTitle{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:20px}.F1KBNa_pickerClose{width:22px;height:22px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute;top:10px;right:10px}.F1KBNa_pickerClose:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_pickerForm{flex:none;gap:8px;display:flex}.F1KBNa_pickerInput{border:1px solid var(--dsw-alias-border-l1);min-width:0;color:var(--dsw-alias-label-primary);background:0 0;border-radius:8px;flex:auto;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_pickerInput:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.F1KBNa_tree{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex:auto;min-height:0;padding:4px 2px 4px 4px;overflow:auto scroll}.F1KBNa_treeRow{border-radius:6px;align-items:center;gap:2px;padding-right:4px;display:flex}.F1KBNa_treeRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_treeRow[data-selected]{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 18%, transparent)}.F1KBNa_treeCaret{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_treeCaret:hover{color:var(--dsw-alias-label-primary)}.F1KBNa_treeName{min-width:0;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:6px;flex:auto;align-items:center;gap:6px;padding:2px 4px;font-family:inherit;font-size:12px;line-height:18px;display:flex}.F1KBNa_treeName:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_treeNote{color:var(--dsw-alias-label-tertiary);margin:2px 0;font-size:12px;line-height:18px}.F1KBNa_pickerIcon{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_pickerName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_pickerNote{color:var(--dsw-alias-label-tertiary);flex:none;margin:0;font-size:12px;line-height:18px}.F1KBNa_pickerCheck{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;margin-right:auto;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_groupHead{align-items:center;gap:4px;margin:8px 0 4px;padding-right:8px;display:flex}.F1KBNa_action.F1KBNa_addButton{box-sizing:border-box;border-radius:6px;flex:none;justify-content:center;align-items:center;width:20px;height:20px;min-height:0;padding:0;display:inline-flex}.F1KBNa_groupHead>.F1KBNa_group{margin:0}.F1KBNa_listHead{flex:none;align-items:center;gap:4px;margin:8px 1px 2px;padding-right:8px;display:flex}.F1KBNa_action.F1KBNa_addButton.F1KBNa_listFold{width:26px;height:26px}.F1KBNa_listTitle{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_listTabs{background:var(--dsw-alias-interactive-bg-hover);border-radius:8px;flex:auto;gap:2px;min-width:0;padding:2px;display:flex}.F1KBNa_listTab{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:6px;flex:1;justify-content:center;align-items:center;gap:6px;padding:3px 8px;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_tabCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums}.F1KBNa_listTab[aria-selected=true]{background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary)}.F1KBNa_commentRow{box-sizing:border-box;width:100%;color:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;padding:6px 8px;display:block}.F1KBNa_commentRow:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_commentHead{align-items:baseline;gap:6px;min-width:0;display:flex}.F1KBNa_commentLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);font:var(--dsw-font-markdown-code-block);font-size:11px;line-height:16px;overflow:hidden}.F1KBNa_commentLost{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;line-height:16px}.F1KBNa_commentTitle{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);font-size:12px;line-height:18px;display:block;overflow:hidden}.F1KBNa_listEmpty{color:var(--dsw-alias-label-tertiary);margin:8px 12px;font-size:12px;line-height:18px}.F1KBNa_emptyActions{flex-wrap:wrap;justify-content:center;gap:8px;display:flex}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowMenuAnchor{display:none}.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:center;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;margin-left:4px;font-size:12px;line-height:18px;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(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsh-diff-del-color,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_panelDocked .F1KBNa_diffHeader{background:var(--dsw-alias-bg-base)}.F1KBNa_diffPath{appearance:none;min-width:0;font:inherit;text-overflow:ellipsis;color:var(--dsw-alias-label-primary);background:0 0;border:0;flex:1;margin-left:4px;padding:0;font-size:12px;line-height:18px;position:relative;top:1px}.F1KBNa_diffPath:focus{outline:none}.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_gotoBox{background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;align-items:center;gap:8px;padding:12px;display:flex}.F1KBNa_gotoInput{border:1px solid var(--dsw-alias-border-l2);width:8em;color:inherit;font:inherit;background:0 0;border-radius:8px;padding:4px 8px}.F1KBNa_divider{background:var(--dsw-alias-border-l1);align-self:stretch;width:1px;margin:2px 0}.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_actionChord{color:var(--dsw-alias-label-tertiary);margin-left:6px;font-size:11px}.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{isolation:isolate;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffBody{overscroll-behavior:none;min-width:0;font:var(--dsw-font-markdown-code-block);-webkit-text-size-adjust:100%;text-size-adjust:100%;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_blockActionsDivider{background:var(--dsw-alias-border-l2);flex:none;align-self:stretch;width:1px;margin:2px 0}.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_searchToggle{border:1px solid var(--dsw-alias-border-l1);min-height:25px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;justify-content:center;align-items:center;padding:4px 6px;display:inline-flex}.F1KBNa_searchToggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_searchToggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchMatch{color:inherit;background-color:#facc1542;border-radius:2px}.F1KBNa_searchMatchCurrent{color:inherit;background-color:#facc1599;border-radius:2px}.F1KBNa_blockFlash{z-index:3;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_diffFlashFade;position:absolute;left:0;right:0}.F1KBNa_blockFlashShake{animation:.7s ease-out forwards F1KBNa_diffFlashShake}.F1KBNa_discussionRow{background:var(--dsw-alias-bg-base);display:table-row}.F1KBNa_discussionCell{display:table-cell}.F1KBNa_discussionPin{z-index:2;width:0;height:0;position:sticky;left:0}.F1KBNa_discussion{z-index:2;box-sizing:border-box;border-left:3px solid var(--dsw-alias-state-business-primary);box-shadow:inset 0 1px 0 0 color-mix(in srgb, var(--dsw-alias-label-secondary) 55%, transparent), inset 0 -1px 0 0 color-mix(in srgb, var(--dsw-alias-label-secondary) 55%, transparent), inset -1px 0 0 0 color-mix(in srgb, var(--dsw-alias-label-secondary) 55%, transparent);cursor:default;background:0 0;flex-direction:column;display:flex;position:absolute;top:0;left:0;overflow:hidden}.F1KBNa_discussionHead{font:var(--dsw-font-markdown-code-block)}.F1KBNa_discussionBody,.F1KBNa_threadFontProbe{font:var(--dsw-font-markdown-base);font-size:calc(var(--dsh-content-font-size,14px) - 2px)}.F1KBNa_threadFontProbe{visibility:hidden;pointer-events:none;width:0;height:0;position:absolute;overflow:hidden}.F1KBNa_discussionBody{flex-direction:column;flex:auto;min-height:0;padding:0 12px;display:flex;overflow:hidden}.F1KBNa_discussion[data-lost]{border-left-color:var(--dsw-alias-label-secondary);background:repeating-linear-gradient(135deg, var(--dsw-alias-interactive-bg-hover) 0 4px, transparent 4px 8px);background-origin:border-box}.F1KBNa_discussion[data-lost] .F1KBNa_discussionSend,.F1KBNa_discussion[data-lost] .F1KBNa_discussionSend:hover:not(:disabled),.F1KBNa_discussion[data-lost] .F1KBNa_discussionSend:disabled{background:var(--dsw-alias-label-secondary);border-color:var(--dsw-alias-label-secondary);color:var(--dsw-alias-label-primary-foreground)}.F1KBNa_discussion[data-lost] .F1KBNa_discussionUser{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 30%, transparent)}.F1KBNa_discussionAnswer{color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;margin:0;padding:0;font-family:inherit;line-height:22px}.F1KBNa_discussionUser{box-sizing:border-box;background:var(--dsw-specific-bubble,var(--dsw-alias-bg-layer-2,var(--dsw-alias-interactive-bg-hover)));width:fit-content;max-width:82%;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;border-radius:8px 0 8px 8px;margin:6.6px 0 6.6px auto;padding:4.4px 11px;font-family:inherit;line-height:22px}.F1KBNa_discussionCode{box-sizing:border-box;font:var(--dsw-font-markdown-code);font-family:var(--ds-font-family-code);background:color-mix(in srgb, var(--dsw-alias-markdown-inline-code,var(--dsw-alias-interactive-bg-hover-solid)) 90%, var(--dsw-alias-label-secondary));border:.5px solid var(--dsw-alias-border-l1);border-radius:6px;align-items:center;padding:0 5px;font-size:.875em;line-height:16px;display:inline-flex}.F1KBNa_discussionBody strong{font-weight:700}.F1KBNa_discussionNote{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;padding:0;font-family:inherit;line-height:22px}.F1KBNa_discussionNote[data-diff-discussion-hidden]{color:var(--dsw-alias-label-tertiary)}.F1KBNa_discussionDots{margin-left:1px}.F1KBNa_discussionDots>span{animation:1.2s ease-in-out infinite F1KBNa_discussionDot}.F1KBNa_discussionDots>span:nth-child(2){animation-delay:.15s}.F1KBNa_discussionDots>span:nth-child(3){animation-delay:.3s}@keyframes F1KBNa_discussionDot{0%,60%,to{opacity:.25}30%{opacity:1}}.F1KBNa_quoteLines{table-layout:fixed;border-spacing:0;width:calc(100% + 27px);min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);line-height:var(--dsh-diff-line-height,22px);background:color-mix(in srgb, var(--dsw-alias-interactive-bg-hover) 55%, transparent);margin:0 -12px 0 -15px;display:table}.F1KBNa_quoteAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 12%, transparent)}.F1KBNa_quoteDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 13%, transparent)}.F1KBNa_quoteLine{font-size:calc(1em * var(--dsh-diff-font-scale,1));height:var(--dsh-diff-line-height,22px);display:table-row}.F1KBNa_quoteCode{display:table-cell}.F1KBNa_quoteText{white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;display:block}.F1KBNa_quoteNoWrap .F1KBNa_quoteText{white-space:pre;overflow-wrap:normal;overflow:hidden}.F1KBNa_quoteNoWrap .F1KBNa_quoteText:after{content:\"\";width:calc(var(--dsh-diff-quote-width,0px) + 100%);display:inline-block}.F1KBNa_quoteSplit{align-self:stretch;align-items:flex-start;margin:0 -12px;display:flex}.F1KBNa_quoteSplitSide{flex:1 1 0;min-width:0}.F1KBNa_quoteSplitSide+.F1KBNa_quoteSplitSide{border-left:1px solid var(--dsw-alias-border-l2)}.F1KBNa_quoteSplitTable{table-layout:fixed;border-spacing:0;width:100%;display:table}.F1KBNa_quoteNoWrap .F1KBNa_quoteSplit [data-diff-quote-side=left] .F1KBNa_quoteText:after{content:\"\";width:calc(var(--dsh-quote-width-left,0px) + 100%);display:inline-block}.F1KBNa_quoteNoWrap .F1KBNa_quoteSplit [data-diff-quote-side=right] .F1KBNa_quoteText:after{content:\"\";width:calc(var(--dsh-quote-width-right,0px) + 100%);display:inline-block}.F1KBNa_discussionHead{box-sizing:border-box;flex:none;align-items:center;gap:8px;height:22px;padding:0 12px;font-size:12px;line-height:16px;display:flex}.F1KBNa_discussionCompose{box-sizing:border-box;flex:none;align-items:flex-end;gap:8px;height:44px;margin:0 -6px;padding:0 0 6.6px;display:flex}.F1KBNa_discussionSlack{flex:1 1 0;min-height:0;max-height:22px}.F1KBNa_discussionInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);min-width:0;height:26px;color:var(--dsw-alias-label-primary);cursor:text;border-radius:6px;flex:auto;padding:3px 8px;font-family:inherit;line-height:18px}.F1KBNa_discussionToggle{width:18px;height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_discussionToggle:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_discussionRangeWrap{font:var(--dsw-font-markdown-code-block);flex:none}.F1KBNa_discussionRange{color:var(--dsw-alias-label-tertiary);font-family:inherit}.F1KBNa_discussionInput:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.F1KBNa_discussionInput::placeholder{font-family:inherit;font-size:inherit;color:var(--dsw-alias-label-tertiary)}.F1KBNa_discussionSend{box-sizing:border-box;white-space:nowrap;flex:none;justify-content:center;align-items:center;gap:6px;height:26px;padding-left:9px;padding-right:9px;display:inline-flex}.F1KBNa_rowDiscussed{--diff-row-wash:color-mix(in srgb, var(--dsw-alias-label-secondary) 14%, transparent);background-image:linear-gradient(var(--diff-row-wash), var(--diff-row-wash))}@keyframes F1KBNa_diffFlashFade{0%{opacity:1}to{opacity:0}}@keyframes F1KBNa_diffFlashShake{0%{opacity:1;transform:translateY(0)}10%{transform:translateY(1px)}20%{transform:translateY(-1px)}30%{transform:translateY(1px)}40%{transform:translateY(-1px)}50%{transform:translateY(1px)}60%{transform:translateY(-1px)}70%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(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%;font-size:calc(1em * var(--dsh-diff-font-scale,1));display:table}.F1KBNa_line{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);-webkit-user-select:none;user-select:none;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;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_line>.F1KBNa_gutter{z-index:1;background-color:var(--dsw-alias-markdown-code-block);background-image:linear-gradient(var(--diff-row-tint,transparent), var(--diff-row-tint,transparent)), linear-gradient(var(--diff-row-wash,transparent), var(--diff-row-wash,transparent));position:sticky;left:0}.F1KBNa_line>.F1KBNa_gutter+.F1KBNa_gutter{left:44px}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{--diff-row-tint:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent);background-color:var(--diff-row-tint)}.F1KBNa_add{--diff-row-tint:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent);background-color:var(--diff-row-tint)}.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_presentationSelect{cursor:pointer;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_presentationSelect:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_chip{justify-content:flex-end;align-items:center;gap:5px;min-width:0;padding-right:14px;display:inline-flex}.F1KBNa_chipLabel{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_coverHost{align-items:center;display:inline-flex;position:relative}.F1KBNa_coverCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;align-items:center;gap:4px;padding:6px;display:flex}.F1KBNa_coverPopover{z-index:50;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_coverNotice{z-index:80;pointer-events:none;animation:1.25s ease-out forwards F1KBNa_coverNoticeFade;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_coverNoticeCard{gap:4px;padding:6px 8px}@keyframes F1KBNa_coverNoticeFade{0%,78%{opacity:1}to{opacity:0}}.F1KBNa_coverNoticeGlyph{width:44px;height:44px;color:var(--dsw-alias-label-tertiary);border-radius:10px;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_coverNoticeGlyph[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_coverNoticeGlyph[data-changed]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_coverNoticeText{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.F1KBNa_coverButton{width:32px;height:32px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_coverButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_coverButton[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_presentationHost{align-items:center;display:inline-flex}.F1KBNa_chipPresentation{min-width:36px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:20px;flex:none;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_chipPresentation:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_mirrored{transform:scaleX(-1)}.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:var(--dsh-diff-line-height,22px)}.F1KBNa_subline{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);white-space:pre;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))}.F1KBNa_splitRoot{isolation:isolate;flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;min-height:100%;display:flex}.F1KBNa_splitCol{box-sizing:border-box;flex:1 1 0;min-width:0;overflow:hidden}.F1KBNa_splitDivider{background:var(--dsw-alias-border-l2);flex:0 0 1px}.F1KBNa_splitDiscussions{z-index:3;pointer-events:none;width:100%;height:0;position:absolute;top:0;left:0}.F1KBNa_splitDiscussion{box-sizing:border-box;pointer-events:auto;background:var(--dsw-alias-bg-base);position:absolute;left:0}.F1KBNa_splitSealed,.F1KBNa_splitSealed *{-webkit-user-select:none!important;user-select:none!important}.F1KBNa_splitSealedLeft [data-diff-split-side=left],.F1KBNa_splitSealedLeft [data-diff-split-side=left] *,.F1KBNa_splitSealedRight [data-diff-split-side=right],.F1KBNa_splitSealedRight [data-diff-split-side=right] *{-webkit-user-select:text!important;user-select:text!important}.F1KBNa_splitCol .F1KBNa_gutter,.F1KBNa_splitCol .F1KBNa_code{vertical-align:top}.F1KBNa_splitHScrollRow{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;width:100%;min-width:0;display:flex}.F1KBNa_splitHScroll{overscroll-behavior-x:none;min-width:0;height:var(--dsh-scrollbar-width,8px);flex:1 1 0;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:var(--dsh-scrollbar-width,8px)}.F1KBNa_splitHScroll::-webkit-scrollbar-track{cursor:default}.F1KBNa_splitHScroll::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_splitHScrollFill{height:1px}.F1KBNa_splitLdel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent)}.F1KBNa_intraDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 34%, transparent);text-decoration:line-through}.F1KBNa_intraAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 32%, transparent)}";
|
|
25
25
|
const tagId = "dsh-diff-approval/PendingPanel.module.css";
|
|
26
26
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
27
27
|
const tag = document.createElement("style");
|
|
@@ -31,236 +31,260 @@ window.__ModuleLoader__.load({
|
|
|
31
31
|
document.head.appendChild(tag);
|
|
32
32
|
}
|
|
33
33
|
var PendingPanel_module_css_default = {
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"colorSwatch": "F1KBNa_colorSwatch",
|
|
37
|
-
"diffBody": "F1KBNa_diffBody",
|
|
38
|
-
"readError": "F1KBNa_readError",
|
|
39
|
-
"rowDiscussed": "F1KBNa_rowDiscussed",
|
|
40
|
-
"lines": "F1KBNa_lines",
|
|
41
|
-
"discussionToggle": "F1KBNa_discussionToggle",
|
|
42
|
-
"splitHScrollFill": "F1KBNa_splitHScrollFill",
|
|
43
|
-
"blockActions": "F1KBNa_blockActions",
|
|
44
|
-
"fileListShrink": "F1KBNa_fileListShrink",
|
|
45
|
-
"stepperValue": "F1KBNa_stepperValue",
|
|
46
|
-
"colorPickerPopover": "F1KBNa_colorPickerPopover",
|
|
47
|
-
"diffPath": "F1KBNa_diffPath",
|
|
48
|
-
"splitHScroll": "F1KBNa_splitHScroll",
|
|
49
|
-
"group": "F1KBNa_group",
|
|
50
|
-
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
51
|
-
"row": "F1KBNa_row",
|
|
52
|
-
"settingsGroupText": "F1KBNa_settingsGroupText",
|
|
53
|
-
"discussion": "F1KBNa_discussion",
|
|
54
|
-
"rows": "F1KBNa_rows",
|
|
55
|
-
"discussionDot": "F1KBNa_discussionDot",
|
|
56
|
-
"settingsGroupChevron": "F1KBNa_settingsGroupChevron",
|
|
57
|
-
"vSpacer": "F1KBNa_vSpacer",
|
|
58
|
-
"subline": "F1KBNa_subline",
|
|
59
|
-
"chipLabel": "F1KBNa_chipLabel",
|
|
60
|
-
"discussionRow": "F1KBNa_discussionRow",
|
|
34
|
+
"addCount": "F1KBNa_addCount",
|
|
35
|
+
"emptyState": "F1KBNa_emptyState",
|
|
61
36
|
"diff": "F1KBNa_diff",
|
|
62
|
-
"
|
|
63
|
-
"stepperButtonUp": "F1KBNa_stepperButtonUp",
|
|
64
|
-
"quoteDel": "F1KBNa_quoteDel",
|
|
65
|
-
"colorBackdrop": "F1KBNa_colorBackdrop",
|
|
66
|
-
"intraAdd": "F1KBNa_intraAdd",
|
|
67
|
-
"mirrored": "F1KBNa_mirrored",
|
|
68
|
-
"searchToggle": "F1KBNa_searchToggle",
|
|
69
|
-
"searchMatch": "F1KBNa_searchMatch",
|
|
70
|
-
"coverNotice": "F1KBNa_coverNotice",
|
|
37
|
+
"hint": "F1KBNa_hint",
|
|
71
38
|
"listScroll": "F1KBNa_listScroll",
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"coverCard": "F1KBNa_coverCard",
|
|
79
|
-
"mdPreviewWrap": "F1KBNa_mdPreviewWrap",
|
|
80
|
-
"pickerTitle": "F1KBNa_pickerTitle",
|
|
81
|
-
"splitCol": "F1KBNa_splitCol",
|
|
82
|
-
"searchCount": "F1KBNa_searchCount",
|
|
83
|
-
"confirmCard": "F1KBNa_confirmCard",
|
|
84
|
-
"treeNote": "F1KBNa_treeNote",
|
|
85
|
-
"note": "F1KBNa_note",
|
|
86
|
-
"splitRoot": "F1KBNa_splitRoot",
|
|
87
|
-
"colorSvCursor": "F1KBNa_colorSvCursor",
|
|
88
|
-
"colorHueCursor": "F1KBNa_colorHueCursor",
|
|
89
|
-
"settingsRowDesc": "F1KBNa_settingsRowDesc",
|
|
90
|
-
"fileList": "F1KBNa_fileList",
|
|
91
|
-
"rowMenuAnchor": "F1KBNa_rowMenuAnchor",
|
|
39
|
+
"divergedHint": "F1KBNa_divergedHint",
|
|
40
|
+
"colorSv": "F1KBNa_colorSv",
|
|
41
|
+
"stepperButton": "F1KBNa_stepperButton",
|
|
42
|
+
"treeCaret": "F1KBNa_treeCaret",
|
|
43
|
+
"blockActionsDivider": "F1KBNa_blockActionsDivider",
|
|
44
|
+
"discussionRangeWrap": "F1KBNa_discussionRangeWrap",
|
|
92
45
|
"pickerNote": "F1KBNa_pickerNote",
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"split": "F1KBNa_split",
|
|
99
|
-
"langLabel": "F1KBNa_langLabel",
|
|
100
|
-
"fileListFloat": "F1KBNa_fileListFloat",
|
|
101
|
-
"addButton": "F1KBNa_addButton",
|
|
102
|
-
"searchMatchCurrent": "F1KBNa_searchMatchCurrent",
|
|
103
|
-
"importNote": "F1KBNa_importNote",
|
|
104
|
-
"discussionNote": "F1KBNa_discussionNote",
|
|
105
|
-
"states": "F1KBNa_states",
|
|
106
|
-
"settingsRowText": "F1KBNa_settingsRowText",
|
|
107
|
-
"noteCentered": "F1KBNa_noteCentered",
|
|
108
|
-
"discussionBody": "F1KBNa_discussionBody",
|
|
109
|
-
"diffHeader": "F1KBNa_diffHeader",
|
|
110
|
-
"colorValue": "F1KBNa_colorValue",
|
|
111
|
-
"diffPreview": "F1KBNa_diffPreview",
|
|
112
|
-
"mdPreviewDouble": "F1KBNa_mdPreviewDouble",
|
|
113
|
-
"discussionCompose": "F1KBNa_discussionCompose",
|
|
114
|
-
"intraDel": "F1KBNa_intraDel",
|
|
46
|
+
"quoteAdd": "F1KBNa_quoteAdd",
|
|
47
|
+
"colorPickerInput": "F1KBNa_colorPickerInput",
|
|
48
|
+
"gotoInput": "F1KBNa_gotoInput",
|
|
49
|
+
"chipLabel": "F1KBNa_chipLabel",
|
|
50
|
+
"splitHScrollRow": "F1KBNa_splitHScrollRow",
|
|
115
51
|
"iconAction": "F1KBNa_iconAction",
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
"
|
|
52
|
+
"footerButtons": "F1KBNa_footerButtons",
|
|
53
|
+
"kindHint": "F1KBNa_kindHint",
|
|
54
|
+
"del": "F1KBNa_del",
|
|
55
|
+
"missingHint": "F1KBNa_missingHint",
|
|
56
|
+
"rowDiscussed": "F1KBNa_rowDiscussed",
|
|
57
|
+
"tree": "F1KBNa_tree",
|
|
58
|
+
"states": "F1KBNa_states",
|
|
122
59
|
"diffPreviewScroll": "F1KBNa_diffPreviewScroll",
|
|
123
|
-
"
|
|
124
|
-
"line": "F1KBNa_line",
|
|
125
|
-
"badgeCount": "F1KBNa_badgeCount",
|
|
126
|
-
"overviewMarker": "F1KBNa_overviewMarker",
|
|
127
|
-
"searchToggleOn": "F1KBNa_searchToggleOn",
|
|
128
|
-
"colorPickerPanel": "F1KBNa_colorPickerPanel",
|
|
60
|
+
"settingsGroupDesc": "F1KBNa_settingsGroupDesc",
|
|
129
61
|
"confirmBackdrop": "F1KBNa_confirmBackdrop",
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
"rowFailed": "F1KBNa_rowFailed",
|
|
137
|
-
"settingsPage": "F1KBNa_settingsPage",
|
|
138
|
-
"discussionUser": "F1KBNa_discussionUser",
|
|
139
|
-
"header": "F1KBNa_header",
|
|
140
|
-
"detail": "F1KBNa_detail",
|
|
141
|
-
"fileListFloatClosing": "F1KBNa_fileListFloatClosing",
|
|
142
|
-
"blockFlashShake": "F1KBNa_blockFlashShake",
|
|
143
|
-
"discussionRangeWrap": "F1KBNa_discussionRangeWrap",
|
|
144
|
-
"coverNoticeCard": "F1KBNa_coverNoticeCard",
|
|
145
|
-
"fileListKnobIn": "F1KBNa_fileListKnobIn",
|
|
146
|
-
"emptyActions": "F1KBNa_emptyActions",
|
|
62
|
+
"rowMeta": "F1KBNa_rowMeta",
|
|
63
|
+
"blockActions": "F1KBNa_blockActions",
|
|
64
|
+
"markerDel": "F1KBNa_markerDel",
|
|
65
|
+
"subline": "F1KBNa_subline",
|
|
66
|
+
"confirmCard": "F1KBNa_confirmCard",
|
|
67
|
+
"searchMatch": "F1KBNa_searchMatch",
|
|
147
68
|
"badge": "F1KBNa_badge",
|
|
148
|
-
"
|
|
149
|
-
"
|
|
69
|
+
"mdPreviewBody": "F1KBNa_mdPreviewBody",
|
|
70
|
+
"blockPosition": "F1KBNa_blockPosition",
|
|
71
|
+
"splitSealedLeft": "F1KBNa_splitSealedLeft",
|
|
72
|
+
"rowMenuAnchor": "F1KBNa_rowMenuAnchor",
|
|
73
|
+
"rail": "F1KBNa_rail",
|
|
74
|
+
"colorPickerPopover": "F1KBNa_colorPickerPopover",
|
|
75
|
+
"settingsGroupText": "F1KBNa_settingsGroupText",
|
|
76
|
+
"badgeLabel": "F1KBNa_badgeLabel",
|
|
77
|
+
"lines": "F1KBNa_lines",
|
|
78
|
+
"fileListFloatClosing": "F1KBNa_fileListFloatClosing",
|
|
79
|
+
"group": "F1KBNa_group",
|
|
80
|
+
"groupHead": "F1KBNa_groupHead",
|
|
81
|
+
"quoteSplit": "F1KBNa_quoteSplit",
|
|
82
|
+
"splitCol": "F1KBNa_splitCol",
|
|
150
83
|
"expand": "F1KBNa_expand",
|
|
151
|
-
"
|
|
152
|
-
"
|
|
84
|
+
"chip": "F1KBNa_chip",
|
|
85
|
+
"discussionRange": "F1KBNa_discussionRange",
|
|
86
|
+
"mdPreviewDouble": "F1KBNa_mdPreviewDouble",
|
|
87
|
+
"coverCard": "F1KBNa_coverCard",
|
|
88
|
+
"fileListShrink": "F1KBNa_fileListShrink",
|
|
89
|
+
"confirmText": "F1KBNa_confirmText",
|
|
90
|
+
"discussionCode": "F1KBNa_discussionCode",
|
|
91
|
+
"stepperButtonUp": "F1KBNa_stepperButtonUp",
|
|
92
|
+
"listTab": "F1KBNa_listTab",
|
|
93
|
+
"colorSvCursor": "F1KBNa_colorSvCursor",
|
|
94
|
+
"diffHeader": "F1KBNa_diffHeader",
|
|
95
|
+
"detailEmpty": "F1KBNa_detailEmpty",
|
|
96
|
+
"blockFlash": "F1KBNa_blockFlash",
|
|
97
|
+
"settingsRow": "F1KBNa_settingsRow",
|
|
98
|
+
"kindTag": "F1KBNa_kindTag",
|
|
99
|
+
"splitSealedRight": "F1KBNa_splitSealedRight",
|
|
100
|
+
"context": "F1KBNa_context",
|
|
153
101
|
"pickerForm": "F1KBNa_pickerForm",
|
|
154
|
-
"
|
|
155
|
-
"
|
|
102
|
+
"importNote": "F1KBNa_importNote",
|
|
103
|
+
"searchBar": "F1KBNa_searchBar",
|
|
104
|
+
"langLabel": "F1KBNa_langLabel",
|
|
105
|
+
"toggleThumb": "F1KBNa_toggleThumb",
|
|
106
|
+
"bulkActions": "F1KBNa_bulkActions",
|
|
156
107
|
"noticeButton": "F1KBNa_noticeButton",
|
|
108
|
+
"discussionDot": "F1KBNa_discussionDot",
|
|
109
|
+
"listHead": "F1KBNa_listHead",
|
|
157
110
|
"gutter": "F1KBNa_gutter",
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"coverPopover": "F1KBNa_coverPopover",
|
|
161
|
-
"presentationSelect": "F1KBNa_presentationSelect",
|
|
162
|
-
"colorPickerInputRow": "F1KBNa_colorPickerInputRow",
|
|
111
|
+
"rows": "F1KBNa_rows",
|
|
112
|
+
"settingsRowTitle": "F1KBNa_settingsRowTitle",
|
|
163
113
|
"action": "F1KBNa_action",
|
|
164
|
-
"
|
|
114
|
+
"panelFailureText": "F1KBNa_panelFailureText",
|
|
115
|
+
"layer": "F1KBNa_layer",
|
|
116
|
+
"mirrored": "F1KBNa_mirrored",
|
|
117
|
+
"toggleOn": "F1KBNa_toggleOn",
|
|
165
118
|
"actionPrimary": "F1KBNa_actionPrimary",
|
|
166
|
-
"
|
|
167
|
-
"
|
|
168
|
-
"
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"pickerName": "F1KBNa_pickerName",
|
|
174
|
-
"rowMeta": "F1KBNa_rowMeta",
|
|
175
|
-
"settingsReset": "F1KBNa_settingsReset",
|
|
176
|
-
"noticeText": "F1KBNa_noticeText",
|
|
177
|
-
"searchBar": "F1KBNa_searchBar",
|
|
178
|
-
"treeCaret": "F1KBNa_treeCaret",
|
|
179
|
-
"splitRdel": "F1KBNa_splitRdel",
|
|
180
|
-
"fileListKnob": "F1KBNa_fileListKnob",
|
|
119
|
+
"note": "F1KBNa_note",
|
|
120
|
+
"rowHead": "F1KBNa_rowHead",
|
|
121
|
+
"threadFontProbe": "F1KBNa_threadFontProbe",
|
|
122
|
+
"settingsPage": "F1KBNa_settingsPage",
|
|
123
|
+
"colorSwatch": "F1KBNa_colorSwatch",
|
|
124
|
+
"pickerTitle": "F1KBNa_pickerTitle",
|
|
125
|
+
"discussionHead": "F1KBNa_discussionHead",
|
|
181
126
|
"quoteCode": "F1KBNa_quoteCode",
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"
|
|
185
|
-
"
|
|
186
|
-
"
|
|
187
|
-
"
|
|
127
|
+
"settingsRowText": "F1KBNa_settingsRowText",
|
|
128
|
+
"discussionUser": "F1KBNa_discussionUser",
|
|
129
|
+
"readError": "F1KBNa_readError",
|
|
130
|
+
"panelFailureRetry": "F1KBNa_panelFailureRetry",
|
|
131
|
+
"coverNoticeGlyph": "F1KBNa_coverNoticeGlyph",
|
|
132
|
+
"fileListFloat": "F1KBNa_fileListFloat",
|
|
133
|
+
"coverNotice": "F1KBNa_coverNotice",
|
|
134
|
+
"discussionAnswer": "F1KBNa_discussionAnswer",
|
|
135
|
+
"coverNoticeFade": "F1KBNa_coverNoticeFade",
|
|
136
|
+
"coverBackdrop": "F1KBNa_coverBackdrop",
|
|
137
|
+
"listEmpty": "F1KBNa_listEmpty",
|
|
138
|
+
"vSpacer": "F1KBNa_vSpacer",
|
|
139
|
+
"split": "F1KBNa_split",
|
|
140
|
+
"divider": "F1KBNa_divider",
|
|
141
|
+
"pickerIcon": "F1KBNa_pickerIcon",
|
|
142
|
+
"headerActions": "F1KBNa_headerActions",
|
|
143
|
+
"settingsReset": "F1KBNa_settingsReset",
|
|
144
|
+
"coverPopover": "F1KBNa_coverPopover",
|
|
145
|
+
"addButton": "F1KBNa_addButton",
|
|
146
|
+
"diffPath": "F1KBNa_diffPath",
|
|
147
|
+
"commentLost": "F1KBNa_commentLost",
|
|
148
|
+
"stepper": "F1KBNa_stepper",
|
|
149
|
+
"searchInput": "F1KBNa_searchInput",
|
|
150
|
+
"statusBar": "F1KBNa_statusBar",
|
|
151
|
+
"splitLdel": "F1KBNa_splitLdel",
|
|
152
|
+
"colorPickerInputRow": "F1KBNa_colorPickerInputRow",
|
|
153
|
+
"listFold": "F1KBNa_listFold",
|
|
154
|
+
"quoteSplitSide": "F1KBNa_quoteSplitSide",
|
|
155
|
+
"markerAdd": "F1KBNa_markerAdd",
|
|
156
|
+
"overviewRuler": "F1KBNa_overviewRuler",
|
|
157
|
+
"badgeCount": "F1KBNa_badgeCount",
|
|
158
|
+
"settingsGroupBody": "F1KBNa_settingsGroupBody",
|
|
159
|
+
"panelDocked": "F1KBNa_panelDocked",
|
|
160
|
+
"colorPickerPanel": "F1KBNa_colorPickerPanel",
|
|
161
|
+
"pickerCheck": "F1KBNa_pickerCheck",
|
|
162
|
+
"searchCount": "F1KBNa_searchCount",
|
|
163
|
+
"splitHScrollFill": "F1KBNa_splitHScrollFill",
|
|
164
|
+
"settingsGroupHeader": "F1KBNa_settingsGroupHeader",
|
|
165
|
+
"expandExpanded": "F1KBNa_expandExpanded",
|
|
166
|
+
"searchToggle": "F1KBNa_searchToggle",
|
|
167
|
+
"presentationHost": "F1KBNa_presentationHost",
|
|
168
|
+
"line": "F1KBNa_line",
|
|
169
|
+
"close": "F1KBNa_close",
|
|
170
|
+
"discussionInput": "F1KBNa_discussionInput",
|
|
171
|
+
"settingsRowDesc": "F1KBNa_settingsRowDesc",
|
|
172
|
+
"treeName": "F1KBNa_treeName",
|
|
173
|
+
"quoteNoWrap": "F1KBNa_quoteNoWrap",
|
|
174
|
+
"splitDiscussions": "F1KBNa_splitDiscussions",
|
|
175
|
+
"fileListKnobIn": "F1KBNa_fileListKnobIn",
|
|
176
|
+
"splitDiscussion": "F1KBNa_splitDiscussion",
|
|
177
|
+
"listTitle": "F1KBNa_listTitle",
|
|
178
|
+
"commentTitle": "F1KBNa_commentTitle",
|
|
179
|
+
"detail": "F1KBNa_detail",
|
|
188
180
|
"colorPicker": "F1KBNa_colorPicker",
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"quoteLine": "F1KBNa_quoteLine",
|
|
181
|
+
"diffPreviewTitle": "F1KBNa_diffPreviewTitle",
|
|
182
|
+
"colorHueCursor": "F1KBNa_colorHueCursor",
|
|
183
|
+
"discussionCompose": "F1KBNa_discussionCompose",
|
|
193
184
|
"coverButton": "F1KBNa_coverButton",
|
|
185
|
+
"discussionDots": "F1KBNa_discussionDots",
|
|
186
|
+
"discussionSlack": "F1KBNa_discussionSlack",
|
|
187
|
+
"mdPreviewSingle": "F1KBNa_mdPreviewSingle",
|
|
194
188
|
"colorPickerTrigger": "F1KBNa_colorPickerTrigger",
|
|
195
|
-
"
|
|
196
|
-
"
|
|
197
|
-
"
|
|
198
|
-
"
|
|
199
|
-
"
|
|
200
|
-
"
|
|
201
|
-
"
|
|
202
|
-
"wrapActive": "F1KBNa_wrapActive",
|
|
203
|
-
"diffActions": "F1KBNa_diffActions",
|
|
189
|
+
"searchMatchCurrent": "F1KBNa_searchMatchCurrent",
|
|
190
|
+
"confirmActions": "F1KBNa_confirmActions",
|
|
191
|
+
"presentationSelect": "F1KBNa_presentationSelect",
|
|
192
|
+
"panel": "F1KBNa_panel",
|
|
193
|
+
"noticeText": "F1KBNa_noticeText",
|
|
194
|
+
"diffFlashFade": "F1KBNa_diffFlashFade",
|
|
195
|
+
"splitHScroll": "F1KBNa_splitHScroll",
|
|
204
196
|
"resizeHandle": "F1KBNa_resizeHandle",
|
|
205
|
-
"
|
|
206
|
-
"
|
|
207
|
-
"
|
|
208
|
-
"
|
|
197
|
+
"stepperValue": "F1KBNa_stepperValue",
|
|
198
|
+
"colorBackdrop": "F1KBNa_colorBackdrop",
|
|
199
|
+
"quoteText": "F1KBNa_quoteText",
|
|
200
|
+
"coverNoticeCard": "F1KBNa_coverNoticeCard",
|
|
201
|
+
"coverNoticeText": "F1KBNa_coverNoticeText",
|
|
209
202
|
"notice": "F1KBNa_notice",
|
|
210
|
-
"
|
|
211
|
-
"
|
|
212
|
-
"
|
|
213
|
-
"
|
|
203
|
+
"settingsGroup": "F1KBNa_settingsGroup",
|
|
204
|
+
"pickerCard": "F1KBNa_pickerCard",
|
|
205
|
+
"splitRoot": "F1KBNa_splitRoot",
|
|
206
|
+
"listTabs": "F1KBNa_listTabs",
|
|
207
|
+
"splitCols": "F1KBNa_splitCols",
|
|
208
|
+
"delCount": "F1KBNa_delCount",
|
|
209
|
+
"splitSealed": "F1KBNa_splitSealed",
|
|
210
|
+
"actionQuietDisabled": "F1KBNa_actionQuietDisabled",
|
|
211
|
+
"quoteDel": "F1KBNa_quoteDel",
|
|
212
|
+
"discussionBody": "F1KBNa_discussionBody",
|
|
213
|
+
"diffStats": "F1KBNa_diffStats",
|
|
214
|
+
"intraDel": "F1KBNa_intraDel",
|
|
215
|
+
"colorPickerChevron": "F1KBNa_colorPickerChevron",
|
|
216
|
+
"dockHost": "F1KBNa_dockHost",
|
|
217
|
+
"gotoBox": "F1KBNa_gotoBox",
|
|
218
|
+
"splitDivider": "F1KBNa_splitDivider",
|
|
219
|
+
"discussionToggle": "F1KBNa_discussionToggle",
|
|
220
|
+
"diffBodySplit": "F1KBNa_diffBodySplit",
|
|
221
|
+
"discussionRow": "F1KBNa_discussionRow",
|
|
222
|
+
"commentLabel": "F1KBNa_commentLabel",
|
|
223
|
+
"settingsGroupChevron": "F1KBNa_settingsGroupChevron",
|
|
224
|
+
"splitLadd": "F1KBNa_splitLadd",
|
|
225
|
+
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
226
|
+
"colorValue": "F1KBNa_colorValue",
|
|
227
|
+
"overviewMarker": "F1KBNa_overviewMarker",
|
|
228
|
+
"rowFailed": "F1KBNa_rowFailed",
|
|
229
|
+
"searchToggleOn": "F1KBNa_searchToggleOn",
|
|
230
|
+
"actionChord": "F1KBNa_actionChord",
|
|
231
|
+
"mdPreviewWrap": "F1KBNa_mdPreviewWrap",
|
|
214
232
|
"mdPreviewFallback": "F1KBNa_mdPreviewFallback",
|
|
215
|
-
"
|
|
233
|
+
"wrapActive": "F1KBNa_wrapActive",
|
|
234
|
+
"mdPreviewContent": "F1KBNa_mdPreviewContent",
|
|
235
|
+
"pickerName": "F1KBNa_pickerName",
|
|
216
236
|
"rowPath": "F1KBNa_rowPath",
|
|
217
|
-
"
|
|
218
|
-
"
|
|
219
|
-
"
|
|
220
|
-
"
|
|
221
|
-
"rowHead": "F1KBNa_rowHead",
|
|
222
|
-
"discussionCode": "F1KBNa_discussionCode",
|
|
223
|
-
"settingsGroupDesc": "F1KBNa_settingsGroupDesc",
|
|
224
|
-
"colorSv": "F1KBNa_colorSv",
|
|
237
|
+
"fileList": "F1KBNa_fileList",
|
|
238
|
+
"settingsSelector": "F1KBNa_settingsSelector",
|
|
239
|
+
"commentRow": "F1KBNa_commentRow",
|
|
240
|
+
"commentHead": "F1KBNa_commentHead",
|
|
225
241
|
"treeRow": "F1KBNa_treeRow",
|
|
226
|
-
"
|
|
227
|
-
"
|
|
228
|
-
"
|
|
229
|
-
"
|
|
230
|
-
"
|
|
231
|
-
"groupHead": "F1KBNa_groupHead",
|
|
232
|
-
"discussionPin": "F1KBNa_discussionPin",
|
|
233
|
-
"discussionOutdated": "F1KBNa_discussionOutdated",
|
|
234
|
-
"discussionRange": "F1KBNa_discussionRange",
|
|
235
|
-
"markerDel": "F1KBNa_markerDel",
|
|
242
|
+
"diffActions": "F1KBNa_diffActions",
|
|
243
|
+
"diffBody": "F1KBNa_diffBody",
|
|
244
|
+
"actionError": "F1KBNa_actionError",
|
|
245
|
+
"importButton": "F1KBNa_importButton",
|
|
246
|
+
"pickerInput": "F1KBNa_pickerInput",
|
|
236
247
|
"splitRadd": "F1KBNa_splitRadd",
|
|
237
|
-
"
|
|
238
|
-
"
|
|
239
|
-
"
|
|
248
|
+
"code": "F1KBNa_code",
|
|
249
|
+
"floatResizeHandle": "F1KBNa_floatResizeHandle",
|
|
250
|
+
"blockFlashShake": "F1KBNa_blockFlashShake",
|
|
251
|
+
"discussionSend": "F1KBNa_discussionSend",
|
|
252
|
+
"noteCentered": "F1KBNa_noteCentered",
|
|
253
|
+
"header": "F1KBNa_header",
|
|
254
|
+
"add": "F1KBNa_add",
|
|
255
|
+
"chipPresentation": "F1KBNa_chipPresentation",
|
|
256
|
+
"toggle": "F1KBNa_toggle",
|
|
257
|
+
"statusAction": "F1KBNa_statusAction",
|
|
258
|
+
"intraAdd": "F1KBNa_intraAdd",
|
|
259
|
+
"title": "F1KBNa_title",
|
|
260
|
+
"row": "F1KBNa_row",
|
|
261
|
+
"headerEntryCount": "F1KBNa_headerEntryCount",
|
|
262
|
+
"settingsGroupTitle": "F1KBNa_settingsGroupTitle",
|
|
240
263
|
"flexSpacer": "F1KBNa_flexSpacer",
|
|
241
|
-
"
|
|
242
|
-
"
|
|
243
|
-
"
|
|
264
|
+
"discussionPin": "F1KBNa_discussionPin",
|
|
265
|
+
"discussionNote": "F1KBNa_discussionNote",
|
|
266
|
+
"discussionCell": "F1KBNa_discussionCell",
|
|
267
|
+
"quoteLine": "F1KBNa_quoteLine",
|
|
268
|
+
"splitRdel": "F1KBNa_splitRdel",
|
|
269
|
+
"langSelect": "F1KBNa_langSelect",
|
|
270
|
+
"coverHost": "F1KBNa_coverHost",
|
|
271
|
+
"headerEntry": "F1KBNa_headerEntry",
|
|
272
|
+
"discussion": "F1KBNa_discussion",
|
|
273
|
+
"quoteLines": "F1KBNa_quoteLines",
|
|
274
|
+
"treeNote": "F1KBNa_treeNote",
|
|
275
|
+
"colorHue": "F1KBNa_colorHue",
|
|
276
|
+
"addPath": "F1KBNa_addPath",
|
|
277
|
+
"wrap": "F1KBNa_wrap",
|
|
244
278
|
"colorPickerPreview": "F1KBNa_colorPickerPreview",
|
|
245
|
-
"
|
|
246
|
-
"
|
|
247
|
-
"
|
|
279
|
+
"pickerClose": "F1KBNa_pickerClose",
|
|
280
|
+
"quoteSplitTable": "F1KBNa_quoteSplitTable",
|
|
281
|
+
"diffFlashShake": "F1KBNa_diffFlashShake",
|
|
282
|
+
"emptyActions": "F1KBNa_emptyActions",
|
|
248
283
|
"missing": "F1KBNa_missing",
|
|
249
|
-
"
|
|
250
|
-
"
|
|
251
|
-
"
|
|
252
|
-
"
|
|
253
|
-
"addCount": "F1KBNa_addCount",
|
|
254
|
-
"overviewRuler": "F1KBNa_overviewRuler",
|
|
255
|
-
"mdPreviewSingle": "F1KBNa_mdPreviewSingle",
|
|
256
|
-
"divider": "F1KBNa_divider",
|
|
257
|
-
"coverNoticeText": "F1KBNa_coverNoticeText",
|
|
258
|
-
"colorPickerInput": "F1KBNa_colorPickerInput",
|
|
259
|
-
"actionQuietDisabled": "F1KBNa_actionQuietDisabled",
|
|
260
|
-
"discussionAnswer": "F1KBNa_discussionAnswer",
|
|
261
|
-
"confirmText": "F1KBNa_confirmText",
|
|
262
|
-
"diffPreviewTitle": "F1KBNa_diffPreviewTitle",
|
|
263
|
-
"missingHint": "F1KBNa_missingHint"
|
|
284
|
+
"diffPreview": "F1KBNa_diffPreview",
|
|
285
|
+
"tabCount": "F1KBNa_tabCount",
|
|
286
|
+
"panelFailure": "F1KBNa_panelFailure",
|
|
287
|
+
"fileListKnob": "F1KBNa_fileListKnob"
|
|
264
288
|
};
|
|
265
289
|
//#endregion
|
|
266
290
|
//#region lib/types/client/PathPicker.js
|
|
@@ -1176,6 +1200,7 @@ window.__ModuleLoader__.load({
|
|
|
1176
1200
|
jumpDown: "Ctrl+ArrowDown",
|
|
1177
1201
|
copyRef: "Ctrl+L",
|
|
1178
1202
|
addComment: "Ctrl+K",
|
|
1203
|
+
goto: "Ctrl+G",
|
|
1179
1204
|
openSearch: "Ctrl+F",
|
|
1180
1205
|
searchNext: "F3",
|
|
1181
1206
|
searchPrev: "Shift+F3",
|
|
@@ -2834,19 +2859,6 @@ window.__ModuleLoader__.load({
|
|
|
2834
2859
|
return runs;
|
|
2835
2860
|
}
|
|
2836
2861
|
/**
|
|
2837
|
-
* A turn's text with its inline markers gone: what the runs draw, character for character.
|
|
2838
|
-
*
|
|
2839
|
-
* The row measurement uses this, so the rows a block reserves and the text it draws agree. The
|
|
2840
|
-
* markers are not drawn, and counting them would reserve room for characters nobody sees — which
|
|
2841
|
-
* is exactly the kind of whole-row slack that leaves a blank row in the block.
|
|
2842
|
-
*
|
|
2843
|
-
* @param text - the turn's text.
|
|
2844
|
-
* @returns the same text without its `code` and **strong** markers.
|
|
2845
|
-
*/
|
|
2846
|
-
function discussionPlainText(text) {
|
|
2847
|
-
return discussionRuns(text).map((run) => run.text).join("");
|
|
2848
|
-
}
|
|
2849
|
-
/**
|
|
2850
2862
|
* An answer with its blank lines dropped.
|
|
2851
2863
|
*
|
|
2852
2864
|
* The thread is plain text laid out in code rows, so a blank line between two
|
|
@@ -2946,26 +2958,51 @@ window.__ModuleLoader__.load({
|
|
|
2946
2958
|
return next;
|
|
2947
2959
|
}
|
|
2948
2960
|
/**
|
|
2949
|
-
* Re-anchor
|
|
2961
|
+
* Re-anchor a whole file's blocks in one pass.
|
|
2950
2962
|
*
|
|
2951
|
-
*
|
|
2952
|
-
*
|
|
2953
|
-
*
|
|
2954
|
-
*
|
|
2955
|
-
*
|
|
2956
|
-
* outdated: it says so and keeps its quote for the reader, rather than being silently moved
|
|
2957
|
-
* onto whatever took those lines. Only when the whole range is gone from the model does the
|
|
2958
|
-
* block move, and then by line number, back to where the range used to be (see `gone`). The mark
|
|
2959
|
-
* is derived, not sticky — the lines coming back with their quote clears it (GitHub recomputes
|
|
2960
|
-
* `isOutdated` the same way).
|
|
2963
|
+
* Each block is re-anchored exactly as `remapDiscussion` does it — same rules, same identities,
|
|
2964
|
+
* same "nothing moved, same object back" contract — but the row windows every quote is looked up
|
|
2965
|
+
* in are joined ONCE for the whole list. A rebuild (a keep, an edit, a switched file) runs this
|
|
2966
|
+
* over every block a file has, and joining the rows per block is what made the pass cost grow with
|
|
2967
|
+
* the number of comments on a long file.
|
|
2961
2968
|
*
|
|
2962
|
-
* @param
|
|
2969
|
+
* @param discussions - the blocks to re-anchor.
|
|
2963
2970
|
* @param lineOf - the new-file line number of a row, or `undefined` for a row that has none.
|
|
2964
2971
|
* @param textOf - the text of a row, for the quote comparison.
|
|
2965
2972
|
* @param rowCount - how many rows the current model has.
|
|
2966
|
-
* @returns the re-anchored
|
|
2973
|
+
* @returns the re-anchored blocks, in the order they came in.
|
|
2967
2974
|
*/
|
|
2968
|
-
function
|
|
2975
|
+
function remapDiscussions(discussions, lineOf, textOf, rowCount, hasNewLine = () => true) {
|
|
2976
|
+
const windows = windowCache(textOf, rowCount);
|
|
2977
|
+
return discussions.map((discussion) => remapOne(discussion, lineOf, textOf, rowCount, windows, hasNewLine));
|
|
2978
|
+
}
|
|
2979
|
+
/** Every row window of one span, indexed by its text, in one pass over the rows. */
|
|
2980
|
+
function windowIndex(textOf, rowCount, span) {
|
|
2981
|
+
const byText = /* @__PURE__ */ new Map();
|
|
2982
|
+
for (let row = 0; row + span < rowCount; row++) {
|
|
2983
|
+
const parts = [];
|
|
2984
|
+
for (let index = row; index <= row + span; index++) parts.push(index < rowCount ? textOf(index) : "");
|
|
2985
|
+
const text = parts.join("\n");
|
|
2986
|
+
const rows = byText.get(text);
|
|
2987
|
+
if (rows === void 0) byText.set(text, [row]);
|
|
2988
|
+
else rows.push(row);
|
|
2989
|
+
}
|
|
2990
|
+
return byText;
|
|
2991
|
+
}
|
|
2992
|
+
/** One window index per span, built the first time a span is asked for. */
|
|
2993
|
+
function windowCache(textOf, rowCount) {
|
|
2994
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2995
|
+
return (span) => {
|
|
2996
|
+
let index = cache.get(span);
|
|
2997
|
+
if (index === void 0) {
|
|
2998
|
+
index = windowIndex(textOf, rowCount, span);
|
|
2999
|
+
cache.set(span, index);
|
|
3000
|
+
}
|
|
3001
|
+
return index;
|
|
3002
|
+
};
|
|
3003
|
+
}
|
|
3004
|
+
/** The body both entry points share: one block, with the row windows read through `windows`. */
|
|
3005
|
+
function remapOne(discussion, lineOf, textOf, rowCount, windows, hasNewLine) {
|
|
2969
3006
|
const { startLine, endLine } = discussion.anchor;
|
|
2970
3007
|
let start = -1;
|
|
2971
3008
|
let end = -1;
|
|
@@ -2982,7 +3019,7 @@ window.__ModuleLoader__.load({
|
|
|
2982
3019
|
end = row;
|
|
2983
3020
|
}
|
|
2984
3021
|
const quote = discussion.quote;
|
|
2985
|
-
const span = Math.max(0,
|
|
3022
|
+
const span = Math.max(0, (quote ?? "").split("\n").length - 1);
|
|
2986
3023
|
const textAt = (row) => {
|
|
2987
3024
|
const parts = [];
|
|
2988
3025
|
for (let index = row; index <= row + span; index++) parts.push(index < rowCount ? textOf(index) : "");
|
|
@@ -3012,32 +3049,63 @@ window.__ModuleLoader__.load({
|
|
|
3012
3049
|
}
|
|
3013
3050
|
});
|
|
3014
3051
|
};
|
|
3015
|
-
|
|
3052
|
+
/** The block live again on `row`..`row + span` (the same object when it was already there). */
|
|
3053
|
+
const live = (row, last) => row === discussion.anchor.start && last === discussion.anchor.end ? clearOutdated(discussion) : clearOutdated({
|
|
3054
|
+
...discussion,
|
|
3055
|
+
anchor: {
|
|
3056
|
+
...discussion.anchor,
|
|
3057
|
+
start: row,
|
|
3058
|
+
end: last
|
|
3059
|
+
}
|
|
3060
|
+
});
|
|
3061
|
+
/**
|
|
3062
|
+
* The window's text with one line of context on each side, in the current model.
|
|
3063
|
+
*
|
|
3064
|
+
* Compared against the context the thread recorded when it was made (see `quoteContext`): that is
|
|
3065
|
+
* what tells a genuine move of the quoted code from another line elsewhere in the file that happens
|
|
3066
|
+
* to read the same.
|
|
3067
|
+
*/
|
|
3068
|
+
const contextAt = (row) => {
|
|
3069
|
+
const parts = [];
|
|
3070
|
+
for (let index = Math.max(0, row - 1); index <= Math.min(rowCount - 1, row + span + 1); index++) parts.push(textOf(index));
|
|
3071
|
+
return parts.join("\n");
|
|
3072
|
+
};
|
|
3073
|
+
if (quote === void 0) {
|
|
3016
3074
|
if (start === -1) return gone();
|
|
3017
|
-
|
|
3018
|
-
|
|
3075
|
+
return live(start, end);
|
|
3076
|
+
}
|
|
3077
|
+
if (start !== -1 && textAt(start) === quote) return live(start, end);
|
|
3078
|
+
if (start !== -1) {
|
|
3079
|
+
const fingerprint = discussion.quoteContext;
|
|
3080
|
+
let found = -1;
|
|
3081
|
+
for (const row of windows(span).get(quote) ?? []) {
|
|
3082
|
+
let current = false;
|
|
3083
|
+
for (let index = row; index <= row + span; index++) if (hasNewLine(index)) {
|
|
3084
|
+
current = true;
|
|
3085
|
+
break;
|
|
3086
|
+
}
|
|
3087
|
+
if (!current) continue;
|
|
3088
|
+
if (fingerprint !== void 0 && contextAt(row) !== fingerprint) continue;
|
|
3089
|
+
if (found === -1 || Math.abs(row - start) < Math.abs(found - start)) found = row;
|
|
3090
|
+
}
|
|
3091
|
+
if (found !== -1) return clearOutdated({
|
|
3019
3092
|
...discussion,
|
|
3020
3093
|
anchor: {
|
|
3021
3094
|
...discussion.anchor,
|
|
3022
|
-
start,
|
|
3023
|
-
end
|
|
3095
|
+
start: found,
|
|
3096
|
+
end: found + span,
|
|
3097
|
+
startLine: lineOf(found) ?? startLine,
|
|
3098
|
+
endLine: lineOf(found + span) ?? endLine
|
|
3024
3099
|
}
|
|
3025
3100
|
});
|
|
3026
3101
|
}
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
if (textAt(row) !== quote) continue;
|
|
3030
|
-
if (found === -1 || Math.abs(row - start) < Math.abs(found - start)) found = row;
|
|
3031
|
-
}
|
|
3032
|
-
if (found === -1) return start === -1 ? gone() : markOutdated(discussion);
|
|
3033
|
-
return clearOutdated({
|
|
3102
|
+
if (start === -1) return gone();
|
|
3103
|
+
return markOutdated({
|
|
3034
3104
|
...discussion,
|
|
3035
3105
|
anchor: {
|
|
3036
3106
|
...discussion.anchor,
|
|
3037
|
-
start
|
|
3038
|
-
end
|
|
3039
|
-
startLine: lineOf(found) ?? startLine,
|
|
3040
|
-
endLine: lineOf(found + span) ?? endLine
|
|
3107
|
+
start,
|
|
3108
|
+
end
|
|
3041
3109
|
}
|
|
3042
3110
|
});
|
|
3043
3111
|
}
|
|
@@ -19343,7 +19411,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19343
19411
|
guide: [{
|
|
19344
19412
|
order: DIFF_DOCK_GUIDE_ORDER,
|
|
19345
19413
|
title: () => copy.title(),
|
|
19346
|
-
description: () => copy.guideDescription()
|
|
19414
|
+
description: () => copy.guideDescription(),
|
|
19415
|
+
icon: _deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16
|
|
19347
19416
|
}]
|
|
19348
19417
|
}), "diff-approval: right-sidebar tab type");
|
|
19349
19418
|
return true;
|
|
@@ -19400,6 +19469,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19400
19469
|
*/
|
|
19401
19470
|
const threads = /* @__PURE__ */ new Map();
|
|
19402
19471
|
/**
|
|
19472
|
+
* Fired on `window` whenever a session's threads change. The threads are written by the file
|
|
19473
|
+
* detail (which owns them) and read by the list pane (whose comments tab shows them all), so the
|
|
19474
|
+
* event is what keeps the two in step: a reader who posts a comment sees it in the list at once
|
|
19475
|
+
* instead of on the next poll.
|
|
19476
|
+
*/
|
|
19477
|
+
const COMMENTS_CHANGED_EVENT = "dsh-diff-approval:comments-changed";
|
|
19478
|
+
/**
|
|
19403
19479
|
* The comment threads a session's panel is holding.
|
|
19404
19480
|
* @param sessionId - the session, if any.
|
|
19405
19481
|
* @returns the threads by pending entry id; empty when there are none.
|
|
@@ -19415,7 +19491,64 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19415
19491
|
*/
|
|
19416
19492
|
function rememberDiscussions(sessionId, byFile) {
|
|
19417
19493
|
if (sessionId === void 0) return;
|
|
19494
|
+
const before = threads.get(sessionId);
|
|
19418
19495
|
threads.set(sessionId, byFile);
|
|
19496
|
+
if (before === byFile) return;
|
|
19497
|
+
if (typeof window === "undefined") return;
|
|
19498
|
+
window.dispatchEvent(new CustomEvent(COMMENTS_CHANGED_EVENT, { detail: { sessionId } }));
|
|
19499
|
+
}
|
|
19500
|
+
/**
|
|
19501
|
+
* End one comment, wherever it came from.
|
|
19502
|
+
*
|
|
19503
|
+
* The threads belong to the file detail, which writes them here on every change — but the list
|
|
19504
|
+
* pane shows them all and ends them too, and it has no way to reach into another component's
|
|
19505
|
+
* state. So the list asks the memory, and the detail reads the memory back on the event this
|
|
19506
|
+
* fires (see `COMMENTS_CHANGED_EVENT`): one record, one action, whichever pane the reader used.
|
|
19507
|
+
*
|
|
19508
|
+
* @param sessionId - the session the panel is reviewing; nothing is forgotten without one.
|
|
19509
|
+
* @param fileId - the pending entry the thread hangs in.
|
|
19510
|
+
* @param discussionId - the thread to end; an id that is not there changes nothing.
|
|
19511
|
+
*/
|
|
19512
|
+
function forgetDiscussion(sessionId, fileId, discussionId) {
|
|
19513
|
+
if (sessionId === void 0) return;
|
|
19514
|
+
const before = threads.get(sessionId);
|
|
19515
|
+
const list = before?.[fileId];
|
|
19516
|
+
if (list === void 0) return;
|
|
19517
|
+
const next = list.filter((entry) => entry.id !== discussionId);
|
|
19518
|
+
if (next.length === list.length) return;
|
|
19519
|
+
rememberDiscussions(sessionId, {
|
|
19520
|
+
...before,
|
|
19521
|
+
[fileId]: next
|
|
19522
|
+
});
|
|
19523
|
+
}
|
|
19524
|
+
/**
|
|
19525
|
+
* The files this page has been told to stop asking about, by session.
|
|
19526
|
+
*
|
|
19527
|
+
* Keeping or reverting a file asks whether the row should leave the list, and a reader working
|
|
19528
|
+
* through one file's blocks answers that the same way every time. Ticking the box in that prompt is
|
|
19529
|
+
* a fact about this visit rather than a preference — it is not the host's to keep, and a reload
|
|
19530
|
+
* starts clean, exactly like the threads above.
|
|
19531
|
+
*/
|
|
19532
|
+
const quietRemovals = /* @__PURE__ */ new Map();
|
|
19533
|
+
/**
|
|
19534
|
+
* Whether the reader asked not to be asked again about removing one file.
|
|
19535
|
+
* @param sessionId - the session the panel is reviewing; nothing is quiet without one.
|
|
19536
|
+
* @param fileId - the pending entry the question was about.
|
|
19537
|
+
* @returns true when the action should run without the question.
|
|
19538
|
+
*/
|
|
19539
|
+
function removalAskQuiet(sessionId, fileId) {
|
|
19540
|
+
return sessionId === void 0 ? false : quietRemovals.get(sessionId)?.has(fileId) === true;
|
|
19541
|
+
}
|
|
19542
|
+
/**
|
|
19543
|
+
* Stop asking whether one file should leave the list, for the rest of this page.
|
|
19544
|
+
* @param sessionId - the session the panel is reviewing; nothing is recorded without one.
|
|
19545
|
+
* @param fileId - the pending entry the question was about.
|
|
19546
|
+
*/
|
|
19547
|
+
function quietenRemovalAsk(sessionId, fileId) {
|
|
19548
|
+
if (sessionId === void 0) return;
|
|
19549
|
+
const files = quietRemovals.get(sessionId);
|
|
19550
|
+
if (files === void 0) quietRemovals.set(sessionId, /* @__PURE__ */ new Set([fileId]));
|
|
19551
|
+
else files.add(fileId);
|
|
19419
19552
|
}
|
|
19420
19553
|
/** This session's record, created on first use. */
|
|
19421
19554
|
function viewOf(sessionId) {
|
|
@@ -19645,8 +19778,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19645
19778
|
const COMPOSER_HEIGHT_VAR = "--dsh-composer-height";
|
|
19646
19779
|
/** Seat counts as docked when its bottom is this close to the window bottom. */
|
|
19647
19780
|
const DOCKED_TOLERANCE_PX = 48;
|
|
19648
|
-
/** File-list pane width bounds for the manual split drag, in px. */
|
|
19649
|
-
const MIN_LIST_WIDTH_PX = 160;
|
|
19650
19781
|
const MAX_LIST_WIDTH_PX = 560;
|
|
19651
19782
|
/** Inset of the floating file-list card from the code scroll box, in px. */
|
|
19652
19783
|
const FLOAT_LIST_MARGIN_PX = 12;
|
|
@@ -19759,6 +19890,38 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19759
19890
|
})] })]
|
|
19760
19891
|
});
|
|
19761
19892
|
}
|
|
19893
|
+
/** The go-to-line glyph: an arrow landing on a line of code, drawn on the same 14-grid as
|
|
19894
|
+
* `ViewModeIcon`, `MarkdownModeIcon` and `ReturnIcon` so a toolbar of these reads as one set. The
|
|
19895
|
+
* icon library has no "go to line" mark, and a bare `#` beside three line drawings read as a stray
|
|
19896
|
+
* key rather than a control. */
|
|
19897
|
+
function GotoLineIcon({ size = 14 }) {
|
|
19898
|
+
return (0, react_jsx_runtime.jsxs)("svg", {
|
|
19899
|
+
width: size,
|
|
19900
|
+
height: size,
|
|
19901
|
+
viewBox: "0 0 14 14",
|
|
19902
|
+
fill: "none",
|
|
19903
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
19904
|
+
"aria-hidden": "true",
|
|
19905
|
+
children: [
|
|
19906
|
+
(0, react_jsx_runtime.jsx)("path", {
|
|
19907
|
+
d: "M1.5 10.6h11",
|
|
19908
|
+
stroke: "currentColor",
|
|
19909
|
+
strokeWidth: "1.3"
|
|
19910
|
+
}),
|
|
19911
|
+
(0, react_jsx_runtime.jsx)("path", {
|
|
19912
|
+
d: "M7 1.9v5.9",
|
|
19913
|
+
stroke: "currentColor",
|
|
19914
|
+
strokeWidth: "1.3"
|
|
19915
|
+
}),
|
|
19916
|
+
(0, react_jsx_runtime.jsx)("path", {
|
|
19917
|
+
d: "M4.3 5.2 7 7.9l2.7-2.7",
|
|
19918
|
+
stroke: "currentColor",
|
|
19919
|
+
strokeWidth: "1.3",
|
|
19920
|
+
fill: "none"
|
|
19921
|
+
})
|
|
19922
|
+
]
|
|
19923
|
+
});
|
|
19924
|
+
}
|
|
19762
19925
|
/** Return/enter glyph for the comment button: the key's own corner arrow, drawn on
|
|
19763
19926
|
* MarkdownModeIcon's 14-grid so the two read at the same weight. It is what tells
|
|
19764
19927
|
* the user that Enter sends the comment, without spending a row on the hint. */
|
|
@@ -19794,6 +19957,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19794
19957
|
/** A shared canvas for measuring wrapped line heights (CPU-only, no DOM reflow). */
|
|
19795
19958
|
let measureCanvas;
|
|
19796
19959
|
/**
|
|
19960
|
+
* The font `measureCanvas` is currently set to, so a measurer can put its own back before it asks
|
|
19961
|
+
* for a width (see `makeMeasurer`). Every measurer shares the one context, and two of them are
|
|
19962
|
+
* alive at once — the thread's prose and its inline-code chips.
|
|
19963
|
+
*/
|
|
19964
|
+
let measureCanvasFont;
|
|
19965
|
+
/**
|
|
19797
19966
|
* Compute a diff line's visual sub-lines for soft wrap the way VSCode does it:
|
|
19798
19967
|
* a Unicode line-break model — break at whitespace and between any two CJK
|
|
19799
19968
|
* characters (Chinese han, Japanese kana, fullwidth forms), keep Latin and
|
|
@@ -19903,21 +20072,86 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19903
20072
|
return out;
|
|
19904
20073
|
}
|
|
19905
20074
|
/**
|
|
19906
|
-
*
|
|
19907
|
-
*
|
|
19908
|
-
*
|
|
19909
|
-
*
|
|
20075
|
+
* Wrap one line of a turn the way the browser lays it out: the prose by character, each inline-code
|
|
20076
|
+
* chip as one box that cannot be broken.
|
|
20077
|
+
*
|
|
20078
|
+
* `wrapInto` walks characters and nothing else, which is right for the code view and wrong here:
|
|
20079
|
+
* a turn's chip is an inline-flex box (the chat's own inline code, see `.discussionCode`), so half
|
|
20080
|
+
* of a chip never lands on the next line — it moves over whole, and the text after it starts after
|
|
20081
|
+
* the box rather than inside it. Measuring the chip as ordinary text therefore reserves the wrong
|
|
20082
|
+
* number of rows on exactly the lines that carry one, and a row too few is a clipped last line.
|
|
20083
|
+
*
|
|
20084
|
+
* The prose segments are wrapped by `wrapInto` itself, so a line with a chip in it breaks its words
|
|
20085
|
+
* and its spaces exactly where a line without one does; only the chips are placed as boxes.
|
|
20086
|
+
*
|
|
20087
|
+
* @param line - the line's text, markers and all: the runs are read the way the render reads them.
|
|
20088
|
+
* @param room - the width the line wraps in.
|
|
20089
|
+
* @param measure - the prose measurer.
|
|
20090
|
+
* @param chipWidth - the width of one chip's BOX (its text in the chip's own font, plus its padding
|
|
20091
|
+
* and its hairline).
|
|
20092
|
+
* @param tabPx - one tab stop, in px.
|
|
20093
|
+
* @returns the row count for the line.
|
|
20094
|
+
*/
|
|
20095
|
+
function wrapChipRows(line, room, measure, chipWidth, tabPx) {
|
|
20096
|
+
let rows = 1;
|
|
20097
|
+
let used = 0;
|
|
20098
|
+
for (const run of discussionRuns(line)) {
|
|
20099
|
+
if (run.kind === "code") {
|
|
20100
|
+
const width = chipWidth(run.text);
|
|
20101
|
+
if (used > 0 && used + width > room) {
|
|
20102
|
+
rows += 1;
|
|
20103
|
+
used = 0;
|
|
20104
|
+
}
|
|
20105
|
+
used += width;
|
|
20106
|
+
continue;
|
|
20107
|
+
}
|
|
20108
|
+
if (run.text === "") continue;
|
|
20109
|
+
if (used > room) {
|
|
20110
|
+
rows += 1;
|
|
20111
|
+
used = 0;
|
|
20112
|
+
}
|
|
20113
|
+
const parts = wrapInto(run.text, room - used, measure, tabPx);
|
|
20114
|
+
rows += parts.length - 1;
|
|
20115
|
+
const last = parts[parts.length - 1] ?? "";
|
|
20116
|
+
used = parts.length === 1 ? used + charsWidth(Array.from(run.text), measure, tabPx) : charsWidth(Array.from(last), measure, tabPx);
|
|
20117
|
+
}
|
|
20118
|
+
return rows;
|
|
20119
|
+
}
|
|
20120
|
+
/**
|
|
20121
|
+
* Resolve the thread's own prose font for canvas measurement: the font the turns are drawn in.
|
|
20122
|
+
*
|
|
20123
|
+
* That is the app's message text (see `.discussionBody`), and the probe span is what carries it:
|
|
20124
|
+
* the turns themselves may not be in the DOM yet when a block is measured — the first render of a
|
|
20125
|
+
* new annotation happens before its bubble exists — while the probe is there as long as the panel
|
|
20126
|
+
* is. Reading the code cell was what this used to do, back when the thread was set in the code's
|
|
20127
|
+
* own face; the code cell still answers `codeFontOf`, and the chip its own (see `chipFontOf`).
|
|
20128
|
+
*
|
|
20129
|
+
* The string is rebuilt from the individual properties because canvas accepts no line height.
|
|
20130
|
+
*
|
|
20131
|
+
* @returns a canvas `font` string, or undefined when the panel is not mounted.
|
|
20132
|
+
*/
|
|
20133
|
+
function threadFontOf() {
|
|
20134
|
+
const probe = document.querySelector("[data-diff-thread-font]");
|
|
20135
|
+
if (probe === null) return void 0;
|
|
20136
|
+
const computed = getComputedStyle(probe);
|
|
20137
|
+
return `${computed.fontStyle} ${computed.fontWeight} ${computed.fontSize} ${computed.fontFamily}`;
|
|
20138
|
+
}
|
|
20139
|
+
/**
|
|
20140
|
+
* Resolve the inline-code chip's font for canvas measurement: the code face at
|
|
20141
|
+
* `DISCUSSION_CODE_FONT_SCALE` of the thread's prose size, which is what `.discussionCode` asks
|
|
20142
|
+
* for with `font-size: 0.875em`. The family comes off a code cell, which wears the same code token
|
|
20143
|
+
* the chip does.
|
|
19910
20144
|
*
|
|
19911
20145
|
* @returns a canvas `font` string, or undefined when there is no code cell to read.
|
|
19912
20146
|
*/
|
|
19913
|
-
function
|
|
20147
|
+
function chipFontOf() {
|
|
20148
|
+
const prose = document.querySelector("[data-diff-thread-font]");
|
|
19914
20149
|
const code = document.querySelector("[data-diff-code]");
|
|
19915
|
-
if (code === null) return void 0;
|
|
20150
|
+
if (prose === null || code === null) return void 0;
|
|
20151
|
+
const size = Number.parseFloat(getComputedStyle(prose).fontSize);
|
|
20152
|
+
if (!Number.isFinite(size)) return void 0;
|
|
19916
20153
|
const computed = getComputedStyle(code);
|
|
19917
|
-
|
|
19918
|
-
const scale = diffFontScale() / 100;
|
|
19919
|
-
const unscaled = Number.isFinite(size) && scale > 0 ? size / scale : size;
|
|
19920
|
-
return `${computed.fontStyle} ${computed.fontWeight} ${unscaled}px ${computed.fontFamily}`;
|
|
20154
|
+
return `${computed.fontStyle} ${computed.fontWeight} ${size * DISCUSSION_CODE_FONT_SCALE}px ${computed.fontFamily}`;
|
|
19921
20155
|
}
|
|
19922
20156
|
/** Resolve the code cell's computed font for canvas measurement. */
|
|
19923
20157
|
function codeFontOf() {
|
|
@@ -19936,8 +20170,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19936
20170
|
}
|
|
19937
20171
|
const ctx = measureCanvas;
|
|
19938
20172
|
if (ctx === void 0) return void 0;
|
|
19939
|
-
|
|
19940
|
-
|
|
20173
|
+
const current = () => {
|
|
20174
|
+
if (font !== void 0 && measureCanvasFont !== font) {
|
|
20175
|
+
ctx.font = font;
|
|
20176
|
+
measureCanvasFont = font;
|
|
20177
|
+
}
|
|
20178
|
+
return ctx;
|
|
20179
|
+
};
|
|
20180
|
+
const widths = /* @__PURE__ */ new Map();
|
|
20181
|
+
return (text) => {
|
|
20182
|
+
if (text.length !== 1) return current().measureText(text).width;
|
|
20183
|
+
const cached = widths.get(text);
|
|
20184
|
+
if (cached !== void 0) return cached;
|
|
20185
|
+
const width = current().measureText(text).width;
|
|
20186
|
+
widths.set(text, width);
|
|
20187
|
+
return width;
|
|
20188
|
+
};
|
|
19941
20189
|
}
|
|
19942
20190
|
/** How long a question the session has let go stays "queued" before the block hands
|
|
19943
20191
|
* its writing row back. The local submission echo and the host's queue row are a
|
|
@@ -19966,12 +20214,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19966
20214
|
*/
|
|
19967
20215
|
const THREAD_ROW_PX = 22;
|
|
19968
20216
|
/**
|
|
19969
|
-
* The
|
|
19970
|
-
*
|
|
19971
|
-
*
|
|
19972
|
-
*
|
|
20217
|
+
* The share of the thread's prose size an inline-code chip is drawn at (mirrors
|
|
20218
|
+
* `.discussionCode`'s `font-size: 0.875em`, which is the chat's own inline code against its own
|
|
20219
|
+
* message text). The chip is measured in its own font, not in the prose one — a code face at
|
|
20220
|
+
* twelve and a bit pixels is not the UI face at fourteen — so the row count follows the run the
|
|
20221
|
+
* reader actually sees.
|
|
19973
20222
|
*/
|
|
19974
|
-
const
|
|
20223
|
+
const DISCUSSION_CODE_FONT_SCALE = .875;
|
|
19975
20224
|
/** Rows rendered beyond the visible window in each direction. */
|
|
19976
20225
|
const OVERSCAN_ROWS = 8;
|
|
19977
20226
|
/** The identity a file with no discussions shares, so memos stay stable. */
|
|
@@ -20131,6 +20380,25 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20131
20380
|
right
|
|
20132
20381
|
};
|
|
20133
20382
|
}
|
|
20383
|
+
/**
|
|
20384
|
+
* The one-line title a comment is listed under in the comments tab: the first sentence of the first
|
|
20385
|
+
* thing the reader said in it. The thread's first turn IS the annotation (later turns are follow-ups
|
|
20386
|
+
* on the same rows), so that is the comment's own voice; the sentence is cut at its own full stop,
|
|
20387
|
+
* and the list ellipsises whatever is still too long for the column (see `.commentTitle`).
|
|
20388
|
+
*
|
|
20389
|
+
* A thread that has not been sent yet has no turn at all: what the reader has typed so far is its
|
|
20390
|
+
* draft, and that is what the item shows, so a comment being written is not listed as a blank line.
|
|
20391
|
+
* A thread with neither has nothing to quote — an empty comment box the reader placed and left — and
|
|
20392
|
+
* the caller passes in the word for that (see the list).
|
|
20393
|
+
*
|
|
20394
|
+
* @param discussion - the thread to name.
|
|
20395
|
+
* @returns the title, or an empty string when there is nothing to say yet.
|
|
20396
|
+
*/
|
|
20397
|
+
function commentTitle(discussion) {
|
|
20398
|
+
const line = (discussion.messages.find((message) => message.role === "user")?.text ?? discussion.draft ?? "").split("\n").find((text) => text.trim() !== "") ?? "";
|
|
20399
|
+
const stop = /[。!?!?]/.exec(line);
|
|
20400
|
+
return (stop === null ? line : line.slice(0, stop.index + 1)).trim();
|
|
20401
|
+
}
|
|
20134
20402
|
/** The diff body's row class per line kind. */
|
|
20135
20403
|
const ROW_CLASS = {
|
|
20136
20404
|
context: PendingPanel_module_css_default.context,
|
|
@@ -20196,30 +20464,99 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20196
20464
|
return run.text;
|
|
20197
20465
|
});
|
|
20198
20466
|
}
|
|
20199
|
-
function DiscussionQuote({ quote, lines, lang, wrap }) {
|
|
20467
|
+
function DiscussionQuote({ quote, lines, lang, wrap, split }) {
|
|
20200
20468
|
/** The diff's own wash for a quoted row, or nothing for context (and for older threads). */
|
|
20201
20469
|
const wash = (kind) => kind === "add" ? ` ${PendingPanel_module_css_default.quoteAdd}` : kind === "del" ? ` ${PendingPanel_module_css_default.quoteDel}` : "";
|
|
20202
|
-
const
|
|
20203
|
-
|
|
20204
|
-
|
|
20205
|
-
|
|
20206
|
-
|
|
20207
|
-
const
|
|
20208
|
-
if (lineRuns === void 0) content.push(text);
|
|
20209
|
-
else for (const run of lineRuns) content.push((0, react_jsx_runtime.jsx)("span", {
|
|
20210
|
-
style: run.style,
|
|
20211
|
-
children: run.text
|
|
20212
|
-
}, content.length));
|
|
20470
|
+
const texts = (0, react.useMemo)(() => quote.split("\n"), [quote]);
|
|
20471
|
+
/** The quoted lines paired the way the split view pairs the file's rows. */
|
|
20472
|
+
const pairs = (0, react.useMemo)(() => {
|
|
20473
|
+
if (!split) return void 0;
|
|
20474
|
+
return computeSideBySideDiff(texts.map((text, index) => {
|
|
20475
|
+
const line = lines?.[index];
|
|
20213
20476
|
return {
|
|
20214
|
-
|
|
20215
|
-
|
|
20477
|
+
text,
|
|
20478
|
+
kind: line?.kind ?? "context",
|
|
20479
|
+
oldLine: line?.old,
|
|
20480
|
+
newLine: line?.new
|
|
20216
20481
|
};
|
|
20217
|
-
});
|
|
20482
|
+
}), true).pairs;
|
|
20218
20483
|
}, [
|
|
20219
|
-
|
|
20484
|
+
split,
|
|
20485
|
+
texts,
|
|
20486
|
+
lines
|
|
20487
|
+
]);
|
|
20488
|
+
/**
|
|
20489
|
+
* One column's lines and the highlighted runs each draws. Highlighted per column rather than from
|
|
20490
|
+
* one window over the quoted rows: a multi-line construct must not light up across the divider,
|
|
20491
|
+
* which is also how the file's own two columns are lit.
|
|
20492
|
+
*/
|
|
20493
|
+
const sides = (0, react.useMemo)(() => {
|
|
20494
|
+
if (pairs === void 0) return void 0;
|
|
20495
|
+
const build = (which) => {
|
|
20496
|
+
const columnLines = pairs.map((pair) => pair[which]?.text ?? "");
|
|
20497
|
+
return {
|
|
20498
|
+
lines: columnLines,
|
|
20499
|
+
runs: highlightWindow(columnLines, lang, 0, columnLines.length)
|
|
20500
|
+
};
|
|
20501
|
+
};
|
|
20502
|
+
return {
|
|
20503
|
+
left: build("left"),
|
|
20504
|
+
right: build("right")
|
|
20505
|
+
};
|
|
20506
|
+
}, [pairs, lang]);
|
|
20507
|
+
/** One line's nodes: the highlighted runs it draws, or its own text when nothing highlighted it. */
|
|
20508
|
+
const nodesOf = (lineRuns, text) => {
|
|
20509
|
+
if (lineRuns === void 0) return [text];
|
|
20510
|
+
const content = [];
|
|
20511
|
+
for (const run of lineRuns) content.push((0, react_jsx_runtime.jsx)("span", {
|
|
20512
|
+
style: run.style,
|
|
20513
|
+
children: run.text
|
|
20514
|
+
}, content.length));
|
|
20515
|
+
return content;
|
|
20516
|
+
};
|
|
20517
|
+
const rows = (0, react.useMemo)(() => {
|
|
20518
|
+
const runs = highlightWindow(texts, lang, 0, texts.length)?.runs;
|
|
20519
|
+
return texts.map((text, index) => ({
|
|
20520
|
+
content: nodesOf(runs?.[index], text),
|
|
20521
|
+
gutter: lines?.[index]
|
|
20522
|
+
}));
|
|
20523
|
+
}, [
|
|
20524
|
+
texts,
|
|
20220
20525
|
lines,
|
|
20221
20526
|
lang
|
|
20222
20527
|
]);
|
|
20528
|
+
if (pairs !== void 0 && sides !== void 0) {
|
|
20529
|
+
/** The tint a pair's two cells wear, the same way the file's columns tint theirs. */
|
|
20530
|
+
const pairWash = (which, kind) => which === "left" ? wash(kind === "context" ? "context" : "del") : wash(kind === "context" ? "context" : "add");
|
|
20531
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
20532
|
+
className: `${PendingPanel_module_css_default.quoteLines} ${PendingPanel_module_css_default.quoteSplit}${wrap ? "" : " " + PendingPanel_module_css_default.quoteNoWrap}`,
|
|
20533
|
+
"data-diff-discussion-quote": true,
|
|
20534
|
+
children: ["left", "right"].map((which) => (0, react_jsx_runtime.jsx)("div", {
|
|
20535
|
+
className: PendingPanel_module_css_default.quoteSplitSide,
|
|
20536
|
+
"data-diff-quote-side": which,
|
|
20537
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
20538
|
+
className: PendingPanel_module_css_default.quoteSplitTable,
|
|
20539
|
+
children: pairs.map((pair, index) => (0, react_jsx_runtime.jsxs)("div", {
|
|
20540
|
+
className: `${PendingPanel_module_css_default.quoteLine} ${PendingPanel_module_css_default.quotePair}`,
|
|
20541
|
+
"data-diff-quote-pair": true,
|
|
20542
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
20543
|
+
className: PendingPanel_module_css_default.gutter,
|
|
20544
|
+
"data-diff-quote-gutter": true,
|
|
20545
|
+
children: pair[which]?.line ?? ""
|
|
20546
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
20547
|
+
className: `${PendingPanel_module_css_default.quoteCode}${pairWash(which, pair.kind)}`,
|
|
20548
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
20549
|
+
className: PendingPanel_module_css_default.quoteText,
|
|
20550
|
+
"data-diff-quote-text": true,
|
|
20551
|
+
"data-diff-quote-side": which,
|
|
20552
|
+
children: nodesOf(sides[which].runs?.runs?.[index], sides[which].lines[index] ?? "")
|
|
20553
|
+
})
|
|
20554
|
+
})]
|
|
20555
|
+
}, index))
|
|
20556
|
+
})
|
|
20557
|
+
}, which))
|
|
20558
|
+
});
|
|
20559
|
+
}
|
|
20223
20560
|
return (0, react_jsx_runtime.jsx)("div", {
|
|
20224
20561
|
className: `${PendingPanel_module_css_default.quoteLines}${wrap ? "" : " " + PendingPanel_module_css_default.quoteNoWrap}`,
|
|
20225
20562
|
"data-diff-discussion-quote": true,
|
|
@@ -20249,6 +20586,191 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20249
20586
|
}, index))
|
|
20250
20587
|
});
|
|
20251
20588
|
}
|
|
20589
|
+
/** How far outside the viewport a side-by-side thread's card is still drawn, in px: it is a pair's
|
|
20590
|
+
* hop from the edge before the scroll brings it in, and dropping it earlier would flash the card
|
|
20591
|
+
* away at the boundary. */
|
|
20592
|
+
const SPLIT_DISCUSSION_MARGIN_PX = 200;
|
|
20593
|
+
/**
|
|
20594
|
+
* A thread's card: the header (range, fold, ⋯), the quote when the code it was written about is
|
|
20595
|
+
* gone, the turns, and the writing row.
|
|
20596
|
+
*
|
|
20597
|
+
* Every view draws the same card — the single-column code view hangs it in a row of its own below
|
|
20598
|
+
* the rows the thread annotates, and whatever view comes next hangs it under whatever it draws that
|
|
20599
|
+
* anchor as — so it is a component rather than a piece of one view's row stream. What varies per
|
|
20600
|
+
* view is only the wrapper around it and the width it is given.
|
|
20601
|
+
*
|
|
20602
|
+
* @param props - the thread, where it hangs, and the panel's own callbacks.
|
|
20603
|
+
* @returns the card, sized to the rows the panel laid the thread out in.
|
|
20604
|
+
*/
|
|
20605
|
+
function DiscussionBlock({ discussion, label, bodyWidth, lang, menuOpen, asking, t, onToggle, onMenuOpen, onRemove, onDraft, onSend, registerInput, split }) {
|
|
20606
|
+
const rows = discussionRows(discussion);
|
|
20607
|
+
const writingNote = discussion.asking === true && discussion.reply !== void 0 && discussion.reply !== "";
|
|
20608
|
+
const menuItems = [{
|
|
20609
|
+
id: "delete",
|
|
20610
|
+
label: t("action.discussionEnd")
|
|
20611
|
+
}];
|
|
20612
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
20613
|
+
className: PendingPanel_module_css_default.discussion,
|
|
20614
|
+
"data-diff-discussion": true,
|
|
20615
|
+
"data-lost": discussion.lost === true ? "" : void 0,
|
|
20616
|
+
"data-diff-discussion-id": discussion.id,
|
|
20617
|
+
style: {
|
|
20618
|
+
width: Math.max(0, bodyWidth),
|
|
20619
|
+
height: rows * THREAD_ROW_PX
|
|
20620
|
+
},
|
|
20621
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
20622
|
+
className: PendingPanel_module_css_default.discussionHead,
|
|
20623
|
+
children: [
|
|
20624
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
20625
|
+
type: "button",
|
|
20626
|
+
className: PendingPanel_module_css_default.discussionToggle,
|
|
20627
|
+
"data-diff-discussion-toggle": true,
|
|
20628
|
+
"aria-expanded": !discussion.collapsed,
|
|
20629
|
+
"aria-label": t(discussion.collapsed ? "action.discussionExpand" : "action.discussionCollapse"),
|
|
20630
|
+
onClick: () => {
|
|
20631
|
+
onToggle(discussion.id);
|
|
20632
|
+
},
|
|
20633
|
+
children: discussion.collapsed ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 12 }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 12 })
|
|
20634
|
+
}),
|
|
20635
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
20636
|
+
className: PendingPanel_module_css_default.discussionRangeWrap,
|
|
20637
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
20638
|
+
className: PendingPanel_module_css_default.discussionRange,
|
|
20639
|
+
"data-diff-discussion-range": true,
|
|
20640
|
+
children: label
|
|
20641
|
+
})
|
|
20642
|
+
}),
|
|
20643
|
+
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
|
|
20644
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
20645
|
+
open: menuOpen,
|
|
20646
|
+
portal: true,
|
|
20647
|
+
compact: true,
|
|
20648
|
+
align: "end",
|
|
20649
|
+
items: menuItems,
|
|
20650
|
+
onSelect: (id) => {
|
|
20651
|
+
if (id === "delete") onRemove(discussion.id);
|
|
20652
|
+
onMenuOpen(void 0);
|
|
20653
|
+
},
|
|
20654
|
+
onClose: () => {
|
|
20655
|
+
onMenuOpen(void 0);
|
|
20656
|
+
},
|
|
20657
|
+
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
20658
|
+
type: "button",
|
|
20659
|
+
className: PendingPanel_module_css_default.discussionToggle,
|
|
20660
|
+
"data-diff-discussion-menu": true,
|
|
20661
|
+
"aria-label": t("action.more"),
|
|
20662
|
+
onClick: () => {
|
|
20663
|
+
onMenuOpen(menuOpen ? void 0 : discussion.id);
|
|
20664
|
+
},
|
|
20665
|
+
children: "⋯"
|
|
20666
|
+
})
|
|
20667
|
+
})
|
|
20668
|
+
]
|
|
20669
|
+
}), !discussion.collapsed && (0, react_jsx_runtime.jsxs)("div", {
|
|
20670
|
+
className: PendingPanel_module_css_default.discussionBody,
|
|
20671
|
+
children: [
|
|
20672
|
+
discussion.lost === true && discussion.quote !== void 0 && discussion.quote !== "" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("p", {
|
|
20673
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20674
|
+
"data-diff-discussion-quote-label": true,
|
|
20675
|
+
children: t("discussion.outdatedQuote")
|
|
20676
|
+
}), (0, react_jsx_runtime.jsx)(DiscussionQuote, {
|
|
20677
|
+
quote: discussion.quote,
|
|
20678
|
+
lines: discussion.quoteLines,
|
|
20679
|
+
lang,
|
|
20680
|
+
wrap: discussion.quoteWrap === true,
|
|
20681
|
+
split
|
|
20682
|
+
})] }),
|
|
20683
|
+
discussion.hidden !== void 0 && discussion.hidden > 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
20684
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20685
|
+
"data-diff-discussion-hidden": true,
|
|
20686
|
+
children: t("discussion.hidden", { count: discussion.hidden })
|
|
20687
|
+
}),
|
|
20688
|
+
discussion.stopped === true && (discussion.reply === void 0 || discussion.reply === "") && discussion.failed !== true && (0, react_jsx_runtime.jsx)("p", {
|
|
20689
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20690
|
+
"data-diff-discussion-stopped": true,
|
|
20691
|
+
children: t("discussion.stopped")
|
|
20692
|
+
}),
|
|
20693
|
+
discussion.messages.map((message, index) => message.role === "user" ? (0, react_jsx_runtime.jsx)("p", {
|
|
20694
|
+
className: PendingPanel_module_css_default.discussionUser,
|
|
20695
|
+
"data-diff-discussion-user": true,
|
|
20696
|
+
children: discussionNodes(message.text)
|
|
20697
|
+
}, `u${index}`) : (0, react_jsx_runtime.jsx)("p", {
|
|
20698
|
+
className: PendingPanel_module_css_default.discussionAnswer,
|
|
20699
|
+
"data-diff-discussion-reply": true,
|
|
20700
|
+
children: discussionNodes(message.text)
|
|
20701
|
+
}, `a${index}`)),
|
|
20702
|
+
discussion.reply !== void 0 && discussion.reply !== "" ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("p", {
|
|
20703
|
+
className: PendingPanel_module_css_default.discussionAnswer,
|
|
20704
|
+
"data-diff-discussion-reply": true,
|
|
20705
|
+
children: discussionNodes(discussion.reply)
|
|
20706
|
+
}), writingNote && (0, react_jsx_runtime.jsxs)("p", {
|
|
20707
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20708
|
+
"data-diff-discussion-answering": true,
|
|
20709
|
+
children: [t("discussion.answering"), (0, react_jsx_runtime.jsxs)("span", {
|
|
20710
|
+
className: PendingPanel_module_css_default.discussionDots,
|
|
20711
|
+
"data-diff-discussion-dots": true,
|
|
20712
|
+
"aria-hidden": "true",
|
|
20713
|
+
children: [
|
|
20714
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
20715
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
20716
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." })
|
|
20717
|
+
]
|
|
20718
|
+
})]
|
|
20719
|
+
})] }) : discussion.failed === true ? (0, react_jsx_runtime.jsx)("p", {
|
|
20720
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20721
|
+
"data-diff-discussion-failed": true,
|
|
20722
|
+
children: t("discussion.failed")
|
|
20723
|
+
}) : discussion.asking === true ? (0, react_jsx_runtime.jsxs)("p", {
|
|
20724
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20725
|
+
"data-diff-discussion-asking": true,
|
|
20726
|
+
children: [discussion.queued === true ? t("discussion.queued") : t("discussion.thinking"), (0, react_jsx_runtime.jsxs)("span", {
|
|
20727
|
+
className: PendingPanel_module_css_default.discussionDots,
|
|
20728
|
+
"data-diff-discussion-dots": true,
|
|
20729
|
+
"aria-hidden": "true",
|
|
20730
|
+
children: [
|
|
20731
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
20732
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
20733
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." })
|
|
20734
|
+
]
|
|
20735
|
+
})]
|
|
20736
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
20737
|
+
className: PendingPanel_module_css_default.discussionSlack,
|
|
20738
|
+
"data-diff-discussion-slack": true,
|
|
20739
|
+
"aria-hidden": "true"
|
|
20740
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
20741
|
+
className: PendingPanel_module_css_default.discussionCompose,
|
|
20742
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
20743
|
+
className: PendingPanel_module_css_default.discussionInput,
|
|
20744
|
+
"data-diff-discussion-input": true,
|
|
20745
|
+
ref: (element) => {
|
|
20746
|
+
registerInput(discussion.id, element);
|
|
20747
|
+
},
|
|
20748
|
+
value: discussion.draft,
|
|
20749
|
+
placeholder: t("discussion.placeholder"),
|
|
20750
|
+
onChange: (event) => {
|
|
20751
|
+
onDraft(discussion.id, event.target.value);
|
|
20752
|
+
},
|
|
20753
|
+
onKeyDown: (event) => {
|
|
20754
|
+
if (event.key !== "Enter") return;
|
|
20755
|
+
if (event.nativeEvent.isComposing || event.keyCode === 229) return;
|
|
20756
|
+
event.preventDefault();
|
|
20757
|
+
onSend(discussion.id);
|
|
20758
|
+
}
|
|
20759
|
+
}), (0, react_jsx_runtime.jsxs)("button", {
|
|
20760
|
+
type: "button",
|
|
20761
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary} ${PendingPanel_module_css_default.discussionSend}`,
|
|
20762
|
+
"data-diff-discussion-send": true,
|
|
20763
|
+
disabled: asking,
|
|
20764
|
+
onClick: () => {
|
|
20765
|
+
onSend(discussion.id);
|
|
20766
|
+
},
|
|
20767
|
+
children: [t("action.comment"), (0, react_jsx_runtime.jsx)(ReturnIcon, {})]
|
|
20768
|
+
})]
|
|
20769
|
+
})] })
|
|
20770
|
+
]
|
|
20771
|
+
})]
|
|
20772
|
+
});
|
|
20773
|
+
}
|
|
20252
20774
|
/** Chip styling for each intra-line run: removed chars and added chars stand out. */
|
|
20253
20775
|
const INTRA_CLASS = {
|
|
20254
20776
|
same: void 0,
|
|
@@ -20357,6 +20879,63 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20357
20879
|
return target instanceof Element && target.closest("[data-diff-approval-panel]") !== null;
|
|
20358
20880
|
}
|
|
20359
20881
|
/**
|
|
20882
|
+
* What a press inside the panel must NOT drop the text selection for: the content itself, and the
|
|
20883
|
+
* frame that acts on the selection.
|
|
20884
|
+
*
|
|
20885
|
+
* The content mirrors the `user-select` whitelist in `.panel`: the code, the rendered Markdown
|
|
20886
|
+
* preview, a thread's own turns, the code a comment quotes, and any field. Everything else is
|
|
20887
|
+
* chrome (see `.panel`), and a press on chrome ends the selection rather than leaving it standing
|
|
20888
|
+
* — see `onPanelMouseDown`. The frame is the exception that is not content: its 评论 / 保留 / 回退
|
|
20889
|
+
* buttons are about exactly that selection, so dropping it on the way to them would leave them
|
|
20890
|
+
* acting on nothing.
|
|
20891
|
+
*/
|
|
20892
|
+
const KEEPS_SELECTION = [
|
|
20893
|
+
"input",
|
|
20894
|
+
"textarea",
|
|
20895
|
+
"[contenteditable]",
|
|
20896
|
+
"[data-diff-code]",
|
|
20897
|
+
"[data-diff-md-preview-body]",
|
|
20898
|
+
"[data-diff-discussion-user]",
|
|
20899
|
+
"[data-diff-discussion-reply]",
|
|
20900
|
+
"[data-diff-quote-text]",
|
|
20901
|
+
"[data-diff-selection-actions]",
|
|
20902
|
+
"[data-diff-copy]"
|
|
20903
|
+
].join(", ");
|
|
20904
|
+
/**
|
|
20905
|
+
* Whether a press landed on a row the live selection already covers — the highlighted text itself,
|
|
20906
|
+
* or the blank space beside it on the same line.
|
|
20907
|
+
*
|
|
20908
|
+
* Both are inside the code view, which `KEEPS_SELECTION` leaves to the browser, and the browser
|
|
20909
|
+
* keeps the selection for neither: inside the highlight is where a drag that extends it would
|
|
20910
|
+
* begin, and the blank beside it is chrome, which it never clears a selection from. So a plain
|
|
20911
|
+
* press there left the highlight and the frame standing over a gesture that plainly ended. This is
|
|
20912
|
+
* the one press in the content the panel has to end itself (see `onPanelMouseDown`).
|
|
20913
|
+
*
|
|
20914
|
+
* @param target - the element the press landed on.
|
|
20915
|
+
* @param live - the window's selection, still the one the reader had.
|
|
20916
|
+
* @returns whether that selection covers the pressed row.
|
|
20917
|
+
*/
|
|
20918
|
+
function pressOnSelectedRow(target, live) {
|
|
20919
|
+
if (live === null || live.isCollapsed) return false;
|
|
20920
|
+
const unified = rowRangeOf(live);
|
|
20921
|
+
const split = unified === void 0 ? splitRowRangeOf(live) : void 0;
|
|
20922
|
+
const range = unified ?? split;
|
|
20923
|
+
if (range === void 0) return false;
|
|
20924
|
+
const row = target.closest("[data-diff-row], [data-diff-split-row]");
|
|
20925
|
+
if (row === null) return false;
|
|
20926
|
+
let index;
|
|
20927
|
+
if (unified !== void 0) {
|
|
20928
|
+
const value = Number(row.dataset.diffRow);
|
|
20929
|
+
index = Number.isFinite(value) ? value : void 0;
|
|
20930
|
+
} else {
|
|
20931
|
+
const info = splitRowInfoAt(target);
|
|
20932
|
+
if (info === void 0 || range.side !== void 0 && info.side !== range.side) return false;
|
|
20933
|
+
index = info.pairIndex;
|
|
20934
|
+
}
|
|
20935
|
+
if (index === void 0) return false;
|
|
20936
|
+
return index >= range.start && index <= range.end;
|
|
20937
|
+
}
|
|
20938
|
+
/**
|
|
20360
20939
|
* Whether a key event came from a text field that owns its own keys (`Esc`,
|
|
20361
20940
|
* cursor moves). The chat composer is the one that matters: the panel leaves it
|
|
20362
20941
|
* alone even while its own search bar is open.
|
|
@@ -20566,12 +21145,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20566
21145
|
* one side is longer. The gutter and code are top-aligned so sub-lines line up
|
|
20567
21146
|
* across the divider.
|
|
20568
21147
|
*/
|
|
20569
|
-
function SplitSideRow({ index, side, wrapped, runs, kind, isLeft, height, focused, searchHit, searchCurrent, searchQuery, searchOptions, onHover, intra }) {
|
|
21148
|
+
function SplitSideRow({ index, side, wrapped, runs, kind, isLeft, height, focused, discussed, searchHit, searchCurrent, searchQuery, searchOptions, onHover, intra }) {
|
|
20570
21149
|
const tint = isLeft ? kind === "del" || kind === "replace" ? PendingPanel_module_css_default.splitLdel : "" : kind === "add" || kind === "replace" ? PendingPanel_module_css_default.splitRadd : "";
|
|
20571
21150
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
20572
|
-
className: PendingPanel_module_css_default.line
|
|
21151
|
+
className: `${PendingPanel_module_css_default.line}${discussed ? " " + PendingPanel_module_css_default.rowDiscussed : ""}`,
|
|
20573
21152
|
style: { height },
|
|
20574
21153
|
"data-diff-split-row": true,
|
|
21154
|
+
"data-diff-discussion-band": discussed ? "" : void 0,
|
|
20575
21155
|
"data-diff-split-index": index,
|
|
20576
21156
|
"data-diff-split-side": isLeft ? "left" : "right",
|
|
20577
21157
|
"data-diff-focused": focused ? "" : void 0,
|
|
@@ -20590,7 +21170,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20590
21170
|
});
|
|
20591
21171
|
}
|
|
20592
21172
|
/** The two-column (side-by-side) whole-file diff view. */
|
|
20593
|
-
const SplitDiff = (0, react.forwardRef)(function SplitDiff({ file, model, runs, langWrap, tabWidthSpaces, busy, t, selection, leadRows, onBlockKeep, onBlockRevert, onWrapToast, onVisibleLines }, ref) {
|
|
21173
|
+
const SplitDiff = (0, react.forwardRef)(function SplitDiff({ file, model, runs, langWrap, tabWidthSpaces, busy, t, selection, leadRows, onBlockKeep, onBlockRevert, onWrapToast, onVisibleLines, discussions, renderDiscussion, selectionComment }, ref) {
|
|
20594
21174
|
const ROW_HEIGHT_PX = diffLineHeight();
|
|
20595
21175
|
const NAV_ANCHOR_TOLERANCE_PX = ROW_HEIGHT_PX / 4;
|
|
20596
21176
|
const { pairs, pairOfRow } = (0, react.useMemo)(() => computeSideBySideDiff(model.diff.rows, true), [model]);
|
|
@@ -20608,6 +21188,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20608
21188
|
return map;
|
|
20609
21189
|
}, [model, pairOfRow]);
|
|
20610
21190
|
const bodyRef = (0, react.useRef)(null);
|
|
21191
|
+
const splitRootRef = (0, react.useRef)(null);
|
|
20611
21192
|
const [scrollTop, setScrollTop] = (0, react.useState)(0);
|
|
20612
21193
|
const [viewportH, setViewportH] = (0, react.useState)(0);
|
|
20613
21194
|
const [bodyWidth, setBodyWidth] = (0, react.useState)(0);
|
|
@@ -20708,13 +21289,63 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20708
21289
|
if (pairWrapped === null) return null;
|
|
20709
21290
|
return pairWrapped.map((w) => Math.max(w.left?.length ?? 1, w.right?.length ?? 1) * ROW_HEIGHT_PX);
|
|
20710
21291
|
}, [pairWrapped]);
|
|
21292
|
+
/** The model rows a thread annotates: the wash their halves wear (see `rowDiscussed`). */
|
|
21293
|
+
const discussedRows = (0, react.useMemo)(() => {
|
|
21294
|
+
const set = /* @__PURE__ */ new Set();
|
|
21295
|
+
for (const discussion of discussions ?? []) {
|
|
21296
|
+
if (discussion.lost === true) continue;
|
|
21297
|
+
for (let row = Math.max(0, discussion.anchor.start); row <= Math.min(discussion.anchor.end, model.diff.rows.length - 1); row++) set.add(row);
|
|
21298
|
+
}
|
|
21299
|
+
return set;
|
|
21300
|
+
}, [discussions, model]);
|
|
21301
|
+
/**
|
|
21302
|
+
* The pairs that wear the wash: a pair does when either of its rows is one a thread annotates. Per
|
|
21303
|
+
* pair rather than per half, because a commented ADDED line has no old-side row at all — asking each
|
|
21304
|
+
* half about its own row left the empty half bare, and the band is what says the pair carries a
|
|
21305
|
+
* thread. Both halves take it from either row, the way the single-column view washes the whole row.
|
|
21306
|
+
*/
|
|
21307
|
+
const discussedPairs = (0, react.useMemo)(() => {
|
|
21308
|
+
const set = /* @__PURE__ */ new Set();
|
|
21309
|
+
for (const [pair, rows] of pairRowIndices) {
|
|
21310
|
+
const left = rows.left === void 0 ? false : discussedRows.has(rows.left);
|
|
21311
|
+
const right = rows.right === void 0 ? false : discussedRows.has(rows.right);
|
|
21312
|
+
if (left || right) set.add(pair);
|
|
21313
|
+
}
|
|
21314
|
+
return set;
|
|
21315
|
+
}, [pairRowIndices, discussedRows]);
|
|
21316
|
+
/** The threads that hang under each pair, by the row their anchor ends in. */
|
|
21317
|
+
const pairDiscussions = (0, react.useMemo)(() => {
|
|
21318
|
+
const map = /* @__PURE__ */ new Map();
|
|
21319
|
+
for (const discussion of discussions ?? []) {
|
|
21320
|
+
const pair = pairOfRow.get(discussion.anchor.end) ?? pairOfRow.get(discussion.anchor.start);
|
|
21321
|
+
if (pair === void 0) continue;
|
|
21322
|
+
const list = map.get(pair);
|
|
21323
|
+
if (list === void 0) map.set(pair, [discussion]);
|
|
21324
|
+
else list.push(discussion);
|
|
21325
|
+
}
|
|
21326
|
+
return map;
|
|
21327
|
+
}, [discussions, pairOfRow]);
|
|
21328
|
+
/**
|
|
21329
|
+
* The height a pair holds for the threads hanging under it, in px.
|
|
21330
|
+
*
|
|
21331
|
+
* A thread's rows are the thread's own (see `THREAD_ROW_PX`), not the code's, so a block off the
|
|
21332
|
+
* code's grid still lands exactly where the height table says. Both columns reserve this much —
|
|
21333
|
+
* the cards themselves are drawn over both (see the layer below) — which is what keeps the two
|
|
21334
|
+
* halves from drifting apart under a thread either of them shows.
|
|
21335
|
+
*/
|
|
21336
|
+
const discussionPx = (0, react.useCallback)((k) => (pairDiscussions.get(k) ?? []).reduce((px, discussion) => px + discussionRows(discussion) * THREAD_ROW_PX, 0), [pairDiscussions]);
|
|
20711
21337
|
const pairOffsets = (0, react.useMemo)(() => {
|
|
20712
|
-
if (pairHeights === null) return null;
|
|
20713
|
-
const offs = new Array(
|
|
21338
|
+
if (pairHeights === null && pairDiscussions.size === 0) return null;
|
|
21339
|
+
const offs = new Array(pairCount + 1);
|
|
20714
21340
|
offs[0] = 0;
|
|
20715
|
-
for (let i = 0; i <
|
|
21341
|
+
for (let i = 0; i < pairCount; i++) offs[i + 1] = offs[i] + (pairHeights === null ? ROW_HEIGHT_PX : pairHeights[i] ?? ROW_HEIGHT_PX) + discussionPx(i);
|
|
20716
21342
|
return offs;
|
|
20717
|
-
}, [
|
|
21343
|
+
}, [
|
|
21344
|
+
pairHeights,
|
|
21345
|
+
pairCount,
|
|
21346
|
+
discussionPx,
|
|
21347
|
+
pairDiscussions
|
|
21348
|
+
]);
|
|
20718
21349
|
const totalHeight = pairOffsets === null ? pairCount * ROW_HEIGHT_PX : pairOffsets[pairCount] ?? 0;
|
|
20719
21350
|
const off = (k) => pairOffsets === null ? k * ROW_HEIGHT_PX : pairOffsets[Math.max(0, Math.min(k, pairCount))] ?? 0;
|
|
20720
21351
|
const pairHeightAt = (k) => pairHeights === null ? ROW_HEIGHT_PX : pairHeights[k] ?? ROW_HEIGHT_PX;
|
|
@@ -20755,6 +21386,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20755
21386
|
const col = side === "left" ? leftColRef.current : rightColRef.current;
|
|
20756
21387
|
if (strip === null || col === null) return;
|
|
20757
21388
|
col.scrollLeft = strip.scrollLeft;
|
|
21389
|
+
const quotes = splitRootRef.current?.querySelectorAll(`[data-diff-quote-text][data-diff-quote-side="${side}"]`);
|
|
21390
|
+
for (const text of quotes ?? []) text.scrollLeft = strip.scrollLeft;
|
|
20758
21391
|
}, []);
|
|
20759
21392
|
const searchMatches = (0, react.useMemo)(() => searchPairs(pairs, searchQuery, search.options), [
|
|
20760
21393
|
pairs,
|
|
@@ -20931,8 +21564,30 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20931
21564
|
goSearch(direction);
|
|
20932
21565
|
return true;
|
|
20933
21566
|
};
|
|
21567
|
+
/**
|
|
21568
|
+
* The row this view was asked to land on — the comments list's jump into a file that is already open —
|
|
21569
|
+
* and whether it is a thread's own BOX rather than a place in the code. The centering effect below
|
|
21570
|
+
* lands it at the pair that row is in (or at the box hanging under that pair) rather than at its
|
|
21571
|
+
* block's first pair, which is the precision the single-column view has; spent once, like every
|
|
21572
|
+
* landing.
|
|
21573
|
+
*/
|
|
21574
|
+
const landingRowRef = (0, react.useRef)(void 0);
|
|
21575
|
+
/** A row this view was asked to frame and land on rather than a whole block (a go-to-line). */
|
|
21576
|
+
const flashRowRef = (0, react.useRef)(void 0);
|
|
21577
|
+
const land = (0, react.useCallback)((row, toCard = false, rowFlash = false) => {
|
|
21578
|
+
landingRowRef.current = {
|
|
21579
|
+
row,
|
|
21580
|
+
toCard
|
|
21581
|
+
};
|
|
21582
|
+
const pair = pairOfRow.get(row);
|
|
21583
|
+
const block = pair === void 0 ? void 0 : blockIndexByPair.get(pair);
|
|
21584
|
+
if (block !== void 0) setFocus(block);
|
|
21585
|
+
flashRowRef.current = rowFlash ? row : void 0;
|
|
21586
|
+
setFlashKey((key) => key + 1);
|
|
21587
|
+
}, [pairOfRow, blockIndexByPair]);
|
|
20934
21588
|
(0, react.useImperativeHandle)(ref, () => ({
|
|
20935
21589
|
jump,
|
|
21590
|
+
land,
|
|
20936
21591
|
openSearch,
|
|
20937
21592
|
toggleSearch,
|
|
20938
21593
|
closeSearch,
|
|
@@ -20941,6 +21596,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20941
21596
|
toggleMatchWholeWord
|
|
20942
21597
|
}), [
|
|
20943
21598
|
jump,
|
|
21599
|
+
land,
|
|
20944
21600
|
openSearch,
|
|
20945
21601
|
toggleSearch,
|
|
20946
21602
|
closeSearch,
|
|
@@ -20954,7 +21610,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20954
21610
|
if (block === void 0) return;
|
|
20955
21611
|
const body = bodyRef.current;
|
|
20956
21612
|
if (body === null) return;
|
|
20957
|
-
const
|
|
21613
|
+
const landed = landingRowRef.current;
|
|
21614
|
+
landingRowRef.current = void 0;
|
|
21615
|
+
const from = landed === void 0 ? block.start : pairOfRow.get(landed.row) ?? block.start;
|
|
21616
|
+
const target = off(from) + (landed?.toCard === true ? pairHeightAt(from) : 0) - leadRows * ROW_HEIGHT_PX;
|
|
20958
21617
|
const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
|
|
20959
21618
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
20960
21619
|
setScrollTop(clamped);
|
|
@@ -20983,22 +21642,186 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20983
21642
|
};
|
|
20984
21643
|
const blockRanges = (0, react.useMemo)(() => model.blocks.map((block) => blockRangesOf(model.diff.rows, block)), [model]);
|
|
20985
21644
|
const focusedBlock = blockOfPair[focus];
|
|
20986
|
-
const
|
|
20987
|
-
const
|
|
21645
|
+
const flashRow = flashRowRef.current;
|
|
21646
|
+
const flashTop = flashRow !== void 0 ? Math.max(0, off(pairOfRow.get(flashRow) ?? flashRow) - scrollTop) : focusedBlock === void 0 ? 0 : Math.max(0, off(focusedBlock.start) - scrollTop);
|
|
21647
|
+
const flashBottom = flashRow !== void 0 ? Math.min(viewportH > 0 ? viewportH : Number.POSITIVE_INFINITY, off((pairOfRow.get(flashRow) ?? flashRow) + 1) - scrollTop) : focusedBlock === void 0 ? 0 : Math.min(viewportH > 0 ? viewportH : Number.POSITIVE_INFINITY, off(focusedBlock.end + 1) - scrollTop);
|
|
20988
21648
|
const flashHeight = Math.max(0, flashBottom - flashTop);
|
|
20989
21649
|
const blockActionsTop = hoveredBlock === void 0 || blockOfPair[hoveredBlock] === void 0 ? 0 : Math.max(0, Math.min(off(blockOfPair[hoveredBlock].end + 1) - scrollTop, Math.max(0, viewportH - BLOCK_ACTIONS_FRAME_PX)));
|
|
21650
|
+
/**
|
|
21651
|
+
* How a press in the side-by-side view makes a selection. Left to the browser, a drag that crosses
|
|
21652
|
+
* the divider takes in the rest of the column it began in and then the other one upwards — the
|
|
21653
|
+
* pointer's own position decides that, and the selection cannot be written to stop it (a write under
|
|
21654
|
+
* a live drag makes the browser drop the drag instead). An editor has no such problem because a
|
|
21655
|
+
* pointer there is only ever a coordinate: it computes the position inside the editor, so a drag
|
|
21656
|
+
* cannot leave it, which is how VS Code's own text keeps a selection inside its box. The same is
|
|
21657
|
+
* done here for the column the press began in: x is taken inside that column's code cell, so
|
|
21658
|
+
* dragging past the divider keeps the row the pointer is on and the line numbers never join the
|
|
21659
|
+
* selection, and y is taken inside the scroller, which is scrolled here when the pointer leaves it.
|
|
21660
|
+
* Double and triple clicks are still the browser's (`detail` above one), so word and line selection
|
|
21661
|
+
* are unchanged.
|
|
21662
|
+
*
|
|
21663
|
+
* Touch cannot be driven this way — the platform owns the long press, and preventing the touch would
|
|
21664
|
+
* take the scroll with it — so there the other column is simply made unselectable while the press
|
|
21665
|
+
* lasts (see `.splitSealed`), which stops the caret from entering it at all; the cost is that the
|
|
21666
|
+
* caret then resolves to the nearest selectable position rather than to the row under the finger.
|
|
21667
|
+
*/
|
|
21668
|
+
(0, react.useEffect)(() => {
|
|
21669
|
+
const root = splitRootRef.current;
|
|
21670
|
+
const scroller = bodyRef.current;
|
|
21671
|
+
if (root === null || scroller === null) return;
|
|
21672
|
+
const caretApi = document;
|
|
21673
|
+
const canDrive = caretApi.caretRangeFromPoint !== void 0 || caretApi.caretPositionFromPoint !== void 0;
|
|
21674
|
+
let drag = null;
|
|
21675
|
+
let frame = 0;
|
|
21676
|
+
let point = {
|
|
21677
|
+
x: 0,
|
|
21678
|
+
y: 0
|
|
21679
|
+
};
|
|
21680
|
+
let pointerType;
|
|
21681
|
+
/** The position a point names inside `column`: its row for y, and that row's code cell for x. */
|
|
21682
|
+
const positionIn = (column, clientX, clientY) => {
|
|
21683
|
+
const rows = column.querySelectorAll("[data-diff-split-row]");
|
|
21684
|
+
if (rows.length === 0) return void 0;
|
|
21685
|
+
let row = rows[rows.length - 1];
|
|
21686
|
+
for (const candidate of rows) if (clientY < candidate.getBoundingClientRect().bottom) {
|
|
21687
|
+
row = candidate;
|
|
21688
|
+
break;
|
|
21689
|
+
}
|
|
21690
|
+
const box = row.getBoundingClientRect();
|
|
21691
|
+
const y = Math.min(Math.max(clientY, box.top + 1), box.bottom - 1);
|
|
21692
|
+
const code = row.querySelector("[data-diff-code]");
|
|
21693
|
+
if (code === null) return void 0;
|
|
21694
|
+
const cell = code.getBoundingClientRect();
|
|
21695
|
+
const x = Math.min(Math.max(clientX, cell.left + 1), cell.right - 1);
|
|
21696
|
+
const found = caretAtPoint(x, y);
|
|
21697
|
+
if (found !== void 0 && code.contains(found.node)) return found;
|
|
21698
|
+
const edges = textEdgesOf(code);
|
|
21699
|
+
if (edges === void 0) return void 0;
|
|
21700
|
+
return x < (cell.left + cell.right) / 2 ? {
|
|
21701
|
+
node: edges.first,
|
|
21702
|
+
offset: 0
|
|
21703
|
+
} : {
|
|
21704
|
+
node: edges.last,
|
|
21705
|
+
offset: edges.last.length
|
|
21706
|
+
};
|
|
21707
|
+
};
|
|
21708
|
+
const apply = () => {
|
|
21709
|
+
if (drag === null) return;
|
|
21710
|
+
const selection = window.getSelection();
|
|
21711
|
+
const extent = positionIn(drag.column, point.x, point.y);
|
|
21712
|
+
if (selection === null || extent === void 0) return;
|
|
21713
|
+
selection.setBaseAndExtent(drag.anchor.node, drag.anchor.offset, extent.node, extent.offset);
|
|
21714
|
+
};
|
|
21715
|
+
/** One pass per frame: the position first, then a scroll if the pointer is outside the scroller. */
|
|
21716
|
+
const tick = () => {
|
|
21717
|
+
frame = 0;
|
|
21718
|
+
if (drag === null) return;
|
|
21719
|
+
const box = scroller.getBoundingClientRect();
|
|
21720
|
+
const out = point.y < box.top ? point.y - box.top : point.y > box.bottom ? point.y - box.bottom : 0;
|
|
21721
|
+
if (out !== 0) {
|
|
21722
|
+
const step = Math.min(ROW_HEIGHT_PX * 3, Math.max(ROW_HEIGHT_PX, Math.abs(out) / 3));
|
|
21723
|
+
scroller.scrollTop += Math.sign(out) * step;
|
|
21724
|
+
}
|
|
21725
|
+
apply();
|
|
21726
|
+
if (out !== 0) frame = window.requestAnimationFrame(tick);
|
|
21727
|
+
};
|
|
21728
|
+
/** The column a node sits in, or undefined for anything else in the view (a card, a frame). */
|
|
21729
|
+
const columnOf = (target) => {
|
|
21730
|
+
const row = target.closest("[data-diff-split-row]");
|
|
21731
|
+
if (row === null) return void 0;
|
|
21732
|
+
const left = leftColRef.current;
|
|
21733
|
+
const right = rightColRef.current;
|
|
21734
|
+
if (left !== null && left.contains(row)) return left;
|
|
21735
|
+
return right !== null && right.contains(row) ? right : void 0;
|
|
21736
|
+
};
|
|
21737
|
+
const onPointerDown = (event) => {
|
|
21738
|
+
pointerType = event.pointerType;
|
|
21739
|
+
if (event.pointerType === "mouse") return;
|
|
21740
|
+
const target = event.target;
|
|
21741
|
+
if (!(target instanceof Element) || columnOf(target) === void 0) return;
|
|
21742
|
+
const sealed = PendingPanel_module_css_default.splitSealed;
|
|
21743
|
+
const side = PendingPanel_module_css_default.splitSealedLeft;
|
|
21744
|
+
const other = PendingPanel_module_css_default.splitSealedRight;
|
|
21745
|
+
if (sealed === void 0 || side === void 0 || other === void 0) return;
|
|
21746
|
+
document.body.classList.add(sealed, target.closest("[data-diff-split-side=\"left\"]") !== null ? side : other);
|
|
21747
|
+
};
|
|
21748
|
+
const onMouseDown = (event) => {
|
|
21749
|
+
if (!canDrive) return;
|
|
21750
|
+
if (pointerType !== void 0 && pointerType !== "mouse") return;
|
|
21751
|
+
if (event.button !== 0 || event.detail !== 1 || event.shiftKey || event.ctrlKey || event.metaKey || event.altKey) return;
|
|
21752
|
+
const target = event.target;
|
|
21753
|
+
if (!(target instanceof Element)) return;
|
|
21754
|
+
const column = columnOf(target);
|
|
21755
|
+
if (column === void 0) return;
|
|
21756
|
+
const anchor = positionIn(column, event.clientX, event.clientY);
|
|
21757
|
+
if (anchor === void 0) return;
|
|
21758
|
+
event.preventDefault();
|
|
21759
|
+
scroller.focus();
|
|
21760
|
+
point = {
|
|
21761
|
+
x: event.clientX,
|
|
21762
|
+
y: event.clientY
|
|
21763
|
+
};
|
|
21764
|
+
drag = {
|
|
21765
|
+
column,
|
|
21766
|
+
anchor
|
|
21767
|
+
};
|
|
21768
|
+
apply();
|
|
21769
|
+
};
|
|
21770
|
+
const onMove = (event) => {
|
|
21771
|
+
if (drag === null) return;
|
|
21772
|
+
point = {
|
|
21773
|
+
x: event.clientX,
|
|
21774
|
+
y: event.clientY
|
|
21775
|
+
};
|
|
21776
|
+
if (frame === 0) frame = window.requestAnimationFrame(tick);
|
|
21777
|
+
};
|
|
21778
|
+
const release = () => {
|
|
21779
|
+
const sealed = PendingPanel_module_css_default.splitSealed;
|
|
21780
|
+
const side = PendingPanel_module_css_default.splitSealedLeft;
|
|
21781
|
+
const other = PendingPanel_module_css_default.splitSealedRight;
|
|
21782
|
+
if (sealed !== void 0 && side !== void 0 && other !== void 0) document.body.classList.remove(sealed, side, other);
|
|
21783
|
+
};
|
|
21784
|
+
const stop = () => {
|
|
21785
|
+
drag = null;
|
|
21786
|
+
release();
|
|
21787
|
+
if (frame !== 0) {
|
|
21788
|
+
window.cancelAnimationFrame(frame);
|
|
21789
|
+
frame = 0;
|
|
21790
|
+
}
|
|
21791
|
+
};
|
|
21792
|
+
root.addEventListener("pointerdown", onPointerDown, true);
|
|
21793
|
+
root.addEventListener("mousedown", onMouseDown, true);
|
|
21794
|
+
document.addEventListener("pointermove", onMove, true);
|
|
21795
|
+
document.addEventListener("pointerup", stop, true);
|
|
21796
|
+
document.addEventListener("pointercancel", stop, true);
|
|
21797
|
+
document.addEventListener("touchend", release, true);
|
|
21798
|
+
document.addEventListener("touchcancel", release, true);
|
|
21799
|
+
window.addEventListener("blur", stop);
|
|
21800
|
+
return () => {
|
|
21801
|
+
root.removeEventListener("pointerdown", onPointerDown, true);
|
|
21802
|
+
root.removeEventListener("mousedown", onMouseDown, true);
|
|
21803
|
+
document.removeEventListener("pointermove", onMove, true);
|
|
21804
|
+
document.removeEventListener("pointerup", stop, true);
|
|
21805
|
+
document.removeEventListener("pointercancel", stop, true);
|
|
21806
|
+
document.removeEventListener("touchend", release, true);
|
|
21807
|
+
document.removeEventListener("touchcancel", release, true);
|
|
21808
|
+
window.removeEventListener("blur", stop);
|
|
21809
|
+
stop();
|
|
21810
|
+
};
|
|
21811
|
+
}, []);
|
|
20990
21812
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
20991
21813
|
className: PendingPanel_module_css_default.splitRoot,
|
|
21814
|
+
ref: splitRootRef,
|
|
20992
21815
|
onMouseLeave: () => setHoveredBlock(void 0),
|
|
20993
21816
|
children: [
|
|
20994
|
-
(0, react_jsx_runtime.
|
|
21817
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
20995
21818
|
className: `${PendingPanel_module_css_default.diffBody} ${PendingPanel_module_css_default.diffBodySplit}`,
|
|
20996
21819
|
ref: bodyRef,
|
|
20997
21820
|
tabIndex: 0,
|
|
20998
21821
|
onScroll,
|
|
20999
21822
|
style: { tabSize: tabWidthSpaces },
|
|
21000
21823
|
"data-diff-body": true,
|
|
21001
|
-
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
21824
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
21002
21825
|
className: PendingPanel_module_css_default.splitCols,
|
|
21003
21826
|
children: [
|
|
21004
21827
|
(0, react_jsx_runtime.jsx)("div", {
|
|
@@ -21018,7 +21841,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21018
21841
|
const index = start + offset;
|
|
21019
21842
|
const leftRuns = pair.left === void 0 ? void 0 : runs?.oldRuns?.[(pair.left.line ?? 0) - 1];
|
|
21020
21843
|
const sideIndex = pairRowIndices.get(index);
|
|
21021
|
-
return (0, react_jsx_runtime.jsx)(SplitSideRow, {
|
|
21844
|
+
return (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [(0, react_jsx_runtime.jsx)(SplitSideRow, {
|
|
21022
21845
|
index,
|
|
21023
21846
|
side: pair.left,
|
|
21024
21847
|
wrapped: pairWrapped?.[index]?.left,
|
|
@@ -21032,8 +21855,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21032
21855
|
searchQuery,
|
|
21033
21856
|
searchOptions: search.options,
|
|
21034
21857
|
onHover: () => onPairHover(index),
|
|
21035
|
-
intra: sideIndex?.left === void 0 ? void 0 : model.intra.get(sideIndex.left)
|
|
21036
|
-
|
|
21858
|
+
intra: sideIndex?.left === void 0 ? void 0 : model.intra.get(sideIndex.left),
|
|
21859
|
+
discussed: discussedPairs.has(index)
|
|
21860
|
+
}), discussionPx(index) > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
21861
|
+
className: PendingPanel_module_css_default.vSpacer,
|
|
21862
|
+
"data-diff-discussion-space": discussionPx(index),
|
|
21863
|
+
style: { height: discussionPx(index) },
|
|
21864
|
+
"aria-hidden": "true"
|
|
21865
|
+
})] }, index);
|
|
21037
21866
|
}),
|
|
21038
21867
|
end < pairCount && (0, react_jsx_runtime.jsx)("div", {
|
|
21039
21868
|
className: PendingPanel_module_css_default.vSpacer,
|
|
@@ -21061,7 +21890,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21061
21890
|
const index = start + offset;
|
|
21062
21891
|
const rightRuns = pair.right === void 0 ? void 0 : runs?.newRuns?.[(pair.right.line ?? 0) - 1];
|
|
21063
21892
|
const sideIndex = pairRowIndices.get(index);
|
|
21064
|
-
return (0, react_jsx_runtime.jsx)(SplitSideRow, {
|
|
21893
|
+
return (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [(0, react_jsx_runtime.jsx)(SplitSideRow, {
|
|
21065
21894
|
index,
|
|
21066
21895
|
side: pair.right,
|
|
21067
21896
|
wrapped: pairWrapped?.[index]?.right,
|
|
@@ -21075,8 +21904,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21075
21904
|
searchQuery,
|
|
21076
21905
|
searchOptions: search.options,
|
|
21077
21906
|
onHover: () => onPairHover(index),
|
|
21078
|
-
intra: sideIndex?.right === void 0 ? void 0 : model.intra.get(sideIndex.right)
|
|
21079
|
-
|
|
21907
|
+
intra: sideIndex?.right === void 0 ? void 0 : model.intra.get(sideIndex.right),
|
|
21908
|
+
discussed: discussedPairs.has(index)
|
|
21909
|
+
}), discussionPx(index) > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
21910
|
+
className: PendingPanel_module_css_default.vSpacer,
|
|
21911
|
+
"data-diff-discussion-space": discussionPx(index),
|
|
21912
|
+
style: { height: discussionPx(index) },
|
|
21913
|
+
"aria-hidden": "true"
|
|
21914
|
+
})] }, index);
|
|
21080
21915
|
}),
|
|
21081
21916
|
end < pairCount && (0, react_jsx_runtime.jsx)("div", {
|
|
21082
21917
|
className: PendingPanel_module_css_default.vSpacer,
|
|
@@ -21087,7 +21922,35 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21087
21922
|
})
|
|
21088
21923
|
})
|
|
21089
21924
|
]
|
|
21090
|
-
})
|
|
21925
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
21926
|
+
className: PendingPanel_module_css_default.splitDiscussions,
|
|
21927
|
+
"data-diff-split-discussions": true,
|
|
21928
|
+
style: {
|
|
21929
|
+
"--dsh-quote-width-left": `${widestSide.left}ch`,
|
|
21930
|
+
"--dsh-quote-width-right": `${widestSide.right}ch`
|
|
21931
|
+
},
|
|
21932
|
+
children: [...pairDiscussions.entries()].map(([pair, list]) => {
|
|
21933
|
+
const top = off(pair) + pairHeightAt(pair);
|
|
21934
|
+
const height = discussionPx(pair);
|
|
21935
|
+
if (top - scrollTop > viewportH + SPLIT_DISCUSSION_MARGIN_PX || top + height - scrollTop < -200) return null;
|
|
21936
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
21937
|
+
className: PendingPanel_module_css_default.splitDiscussion,
|
|
21938
|
+
"data-discussion-pair": pair,
|
|
21939
|
+
style: {
|
|
21940
|
+
top,
|
|
21941
|
+
width: bodyWidth,
|
|
21942
|
+
height
|
|
21943
|
+
},
|
|
21944
|
+
children: list.map((discussion) => (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderDiscussion?.(discussion, bodyWidth, true) }, discussion.id))
|
|
21945
|
+
}, pair);
|
|
21946
|
+
})
|
|
21947
|
+
})]
|
|
21948
|
+
}),
|
|
21949
|
+
selectionComment !== void 0 && selection !== void 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
21950
|
+
className: PendingPanel_module_css_default.blockActions,
|
|
21951
|
+
"data-diff-selection-actions": true,
|
|
21952
|
+
style: { top: Math.max(0, Math.min(off(selection.end + 1) - scrollTop, Math.max(0, viewportH - 32))) },
|
|
21953
|
+
children: selectionComment
|
|
21091
21954
|
}),
|
|
21092
21955
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
21093
21956
|
className: PendingPanel_module_css_default.splitHScrollRow,
|
|
@@ -21332,10 +22195,48 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21332
22195
|
side: side === "left" ? "old" : "new"
|
|
21333
22196
|
};
|
|
21334
22197
|
}
|
|
22198
|
+
/** The first and last text node inside `root`, or undefined when it holds no text. */
|
|
22199
|
+
function textEdgesOf(root) {
|
|
22200
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
22201
|
+
const first = walker.nextNode();
|
|
22202
|
+
if (!(first instanceof Text)) return void 0;
|
|
22203
|
+
let last = first;
|
|
22204
|
+
for (let node = walker.nextNode(); node !== null; node = walker.nextNode()) if (node instanceof Text) last = node;
|
|
22205
|
+
return {
|
|
22206
|
+
first,
|
|
22207
|
+
last
|
|
22208
|
+
};
|
|
22209
|
+
}
|
|
22210
|
+
/**
|
|
22211
|
+
* The text position a point names, in whichever of the two spellings the browser has — or undefined
|
|
22212
|
+
* when it has neither, which is when the panel has to leave the selection to the browser (see the
|
|
22213
|
+
* split view's own drag).
|
|
22214
|
+
* @param x - client X of the point.
|
|
22215
|
+
* @param y - client Y of the point.
|
|
22216
|
+
* @returns the position, or undefined when the browser cannot resolve one.
|
|
22217
|
+
*/
|
|
22218
|
+
function caretAtPoint(x, y) {
|
|
22219
|
+
const api = document;
|
|
22220
|
+
const range = api.caretRangeFromPoint?.(x, y);
|
|
22221
|
+
if (range !== void 0 && range !== null) return {
|
|
22222
|
+
node: range.startContainer,
|
|
22223
|
+
offset: range.startOffset
|
|
22224
|
+
};
|
|
22225
|
+
const position = api.caretPositionFromPoint?.(x, y);
|
|
22226
|
+
return position === void 0 || position === null ? void 0 : {
|
|
22227
|
+
node: position.offsetNode,
|
|
22228
|
+
offset: position.offset
|
|
22229
|
+
};
|
|
22230
|
+
}
|
|
21335
22231
|
/**
|
|
21336
22232
|
* Derive the selected split pair range per side (a left-column selection
|
|
21337
|
-
* references the old file, a right-column selection the new file).
|
|
21338
|
-
*
|
|
22233
|
+
* references the old file, a right-column selection the new file). The two ends
|
|
22234
|
+
* can only disagree about the side when the selection was not made by the split
|
|
22235
|
+
* view's own drag, which cannot leave its column (see `SplitDiff`) — a keyboard
|
|
22236
|
+
* selection onto the neighbouring column, say, or a touch press. The range then
|
|
22237
|
+
* belongs to the column the selection began in and covers the pairs both ends
|
|
22238
|
+
* name: the pairs are the same list in both halves, so that is the range a
|
|
22239
|
+
* selection that stayed in that half would have made.
|
|
21339
22240
|
*/
|
|
21340
22241
|
function splitRowRangeOf(selection) {
|
|
21341
22242
|
if (selection === null || selection.isCollapsed || selection.rangeCount === 0) return void 0;
|
|
@@ -21343,7 +22244,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21343
22244
|
const startInfo = splitRowInfoAt(range.startContainer);
|
|
21344
22245
|
const endInfo = splitRowInfoAt(range.endContainer);
|
|
21345
22246
|
if (startInfo === void 0 || endInfo === void 0) return void 0;
|
|
21346
|
-
if (startInfo.side !== endInfo.side) return void 0;
|
|
21347
22247
|
let start = startInfo.pairIndex;
|
|
21348
22248
|
let end = endInfo.pairIndex;
|
|
21349
22249
|
if (lineOffsetAt(range.startContainer, range.startOffset) >= lineLengthAt(range.startContainer)) start += 1;
|
|
@@ -21352,7 +22252,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21352
22252
|
return {
|
|
21353
22253
|
start,
|
|
21354
22254
|
end,
|
|
21355
|
-
side: startInfo.side
|
|
22255
|
+
side: splitRowInfoAt(selection.anchorNode)?.side ?? startInfo.side
|
|
21356
22256
|
};
|
|
21357
22257
|
}
|
|
21358
22258
|
/** The code cell in `node`'s visual row, a sibling of its gutter cells. A
|
|
@@ -21566,7 +22466,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21566
22466
|
});
|
|
21567
22467
|
}
|
|
21568
22468
|
/** The selected file's diff, actions, jump controls, and copy toolbar. */
|
|
21569
|
-
function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, landingTop, landingTick, failedMessage, commentSkill, onPasteReference, onAskAgent, watchChat, onToast, t, onAddTypedPath, onKeep, onRevert, onRefreshVcs, onBlockKeep, onBlockRevert, onOpen, onPreviewImage }) {
|
|
22469
|
+
function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, landingTop, landingTick, landingRow, landingCard, onLanded, failedMessage, commentSkill, onPasteReference, onAskAgent, watchChat, onToast, t, onAddTypedPath, onKeep, onRevert, onRefreshVcs, onBlockKeep, onBlockRevert, onOpen, onPreviewImage }) {
|
|
21570
22470
|
/** The path being typed into the header field; null shows the open file's own path. */
|
|
21571
22471
|
const [pathDraft, setPathDraft] = (0, react.useState)(null);
|
|
21572
22472
|
const [langOverride, setLangOverride] = (0, react.useState)(void 0);
|
|
@@ -21637,7 +22537,52 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21637
22537
|
file.newText,
|
|
21638
22538
|
splitView
|
|
21639
22539
|
]);
|
|
21640
|
-
const
|
|
22540
|
+
const splitModel = (0, react.useMemo)(() => splitView ? computeSideBySideDiff(model.diff.rows, true) : null, [splitView, model]);
|
|
22541
|
+
const splitPairs = splitModel?.pairs ?? null;
|
|
22542
|
+
/**
|
|
22543
|
+
* Which model row each pair holds on each side: the side-by-side view selects PAIRS and names one
|
|
22544
|
+
* column (see `splitRowRangeOf`), while everything that reads a selection as lines — the anchor a
|
|
22545
|
+
* comment is written to, and the "this range already has a thread" test — speaks rows.
|
|
22546
|
+
*/
|
|
22547
|
+
const pairRows = (0, react.useMemo)(() => {
|
|
22548
|
+
const map = /* @__PURE__ */ new Map();
|
|
22549
|
+
if (splitModel === null) return map;
|
|
22550
|
+
model.diff.rows.forEach((row, rowIndex) => {
|
|
22551
|
+
const pair = splitModel.pairOfRow.get(rowIndex);
|
|
22552
|
+
if (pair === void 0) return;
|
|
22553
|
+
const entry = map.get(pair) ?? {};
|
|
22554
|
+
if (row.kind !== "add") entry.old = rowIndex;
|
|
22555
|
+
if (row.kind !== "del") entry.new = rowIndex;
|
|
22556
|
+
map.set(pair, entry);
|
|
22557
|
+
});
|
|
22558
|
+
return map;
|
|
22559
|
+
}, [splitModel, model]);
|
|
22560
|
+
/**
|
|
22561
|
+
* The rows a selection names, whichever view made it: the pair range of a side-by-side selection
|
|
22562
|
+
* mapped to that column's rows, and a single-column range left as it is.
|
|
22563
|
+
*
|
|
22564
|
+
* Only the NEW side can be named. A thread is anchored to new-file lines — those are what survive
|
|
22565
|
+
* the model being rebuilt, and what its reference label shows — so a left-column selection (the
|
|
22566
|
+
* old file, code that may not exist any more) has nothing to anchor to: it reads as no rows, and
|
|
22567
|
+
* the comment is not offered on it.
|
|
22568
|
+
*
|
|
22569
|
+
* @param range - the selection to read.
|
|
22570
|
+
* @returns the same lines as a row range, or undefined when the view named none.
|
|
22571
|
+
*/
|
|
22572
|
+
const selectionRows = (range) => {
|
|
22573
|
+
if (range === void 0) return void 0;
|
|
22574
|
+
if (!splitView || range.side === void 0 || splitModel === null) return range;
|
|
22575
|
+
if (range.side !== "new") return void 0;
|
|
22576
|
+
const rows = [];
|
|
22577
|
+
for (let index = range.start; index <= range.end; index++) {
|
|
22578
|
+
const row = pairRows.get(index)?.new;
|
|
22579
|
+
if (row !== void 0) rows.push(row);
|
|
22580
|
+
}
|
|
22581
|
+
return rows.length === 0 ? void 0 : {
|
|
22582
|
+
start: Math.min(...rows),
|
|
22583
|
+
end: Math.max(...rows)
|
|
22584
|
+
};
|
|
22585
|
+
};
|
|
21641
22586
|
(0, react.useEffect)(() => {
|
|
21642
22587
|
if (!previewActive) return;
|
|
21643
22588
|
const body = mdPreviewBodyRef.current;
|
|
@@ -21720,24 +22665,32 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21720
22665
|
const [scrollTop, setScrollTop] = (0, react.useState)(0);
|
|
21721
22666
|
const [viewportHeight, setViewportHeight] = (0, react.useState)(0);
|
|
21722
22667
|
const [bodyWidth, setBodyWidth] = (0, react.useState)(0);
|
|
22668
|
+
/** The go-to-line dialog: whether it is up, and what has been typed into it. */
|
|
22669
|
+
const [gotoOpen, setGotoOpen] = (0, react.useState)(false);
|
|
22670
|
+
const [gotoDraft, setGotoDraft] = (0, react.useState)("");
|
|
22671
|
+
/** The row a go-to-line flashed: its box frames that one row instead of the block around it. */
|
|
22672
|
+
const flashRowRef = (0, react.useRef)(void 0);
|
|
21723
22673
|
const [hScrollbarPx, setHScrollbarPx] = (0, react.useState)(0);
|
|
21724
22674
|
const [hoveredBlock, setHoveredBlock] = (0, react.useState)(void 0);
|
|
21725
22675
|
const [selection, setSelection] = (0, react.useState)(void 0);
|
|
21726
22676
|
const [commentMode, setCommentMode] = (0, react.useState)(commentModeEnabled);
|
|
21727
22677
|
const [discussionsByFile, setDiscussionsByFile] = (0, react.useState)(() => rememberedDiscussions(file.sessionId));
|
|
21728
22678
|
const discussions = discussionsByFile[file.id] ?? EMPTY_DISCUSSIONS;
|
|
22679
|
+
const askingId = (0, react.useMemo)(() => {
|
|
22680
|
+
for (const list of Object.values(discussionsByFile)) {
|
|
22681
|
+
const waiting = list.find((entry) => entry.asking === true);
|
|
22682
|
+
if (waiting !== void 0) return waiting.id;
|
|
22683
|
+
}
|
|
22684
|
+
}, [discussionsByFile]);
|
|
21729
22685
|
const setDiscussions = (update) => {
|
|
21730
22686
|
setDiscussionsByFile((all) => ({
|
|
21731
22687
|
...all,
|
|
21732
22688
|
[file.id]: update(all[file.id] ?? EMPTY_DISCUSSIONS)
|
|
21733
22689
|
}));
|
|
21734
22690
|
};
|
|
21735
|
-
/** Which block's overflow menu is open, if any.
|
|
22691
|
+
/** Which block's overflow menu is open, if any. The card builds the menu's own row (see
|
|
22692
|
+
* `DiscussionBlock`): finishing a thread takes the block, and its rows, away. */
|
|
21736
22693
|
const [discussionMenuFor, setDiscussionMenuFor] = (0, react.useState)(void 0);
|
|
21737
|
-
const discussionMenuItems = (0, react.useMemo)(() => [{
|
|
21738
|
-
id: "delete",
|
|
21739
|
-
label: t("action.discussionEnd")
|
|
21740
|
-
}], [t]);
|
|
21741
22694
|
/** The session's chat, watched so a discussion can show the answer it asked for. */
|
|
21742
22695
|
const [chat, setChat] = (0, react.useState)({
|
|
21743
22696
|
running: false,
|
|
@@ -21779,6 +22732,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21779
22732
|
/** The offset the file now showing was asked to open at, held until the landing
|
|
21780
22733
|
* effect below spends it (that effect runs a render later than the switch). */
|
|
21781
22734
|
const landingTopRef = (0, react.useRef)(void 0);
|
|
22735
|
+
/** The model row a jump to a comment asked for, spent the same way and by the same effect. */
|
|
22736
|
+
const landingRowRef = (0, react.useRef)(void 0);
|
|
22737
|
+
/** Whether that row is a thread's own box rather than a place in the code (see `landingCard`). */
|
|
22738
|
+
const landingCardRef = (0, react.useRef)(false);
|
|
22739
|
+
/** The latest `onLanded`, for the landing effect: it says the ask has been taken, and the panel
|
|
22740
|
+
* then spends it so a pane that mounts later cannot take it again. Read through a ref because the
|
|
22741
|
+
* panel hands a fresh closure on every render, and re-running the landing effect for that would
|
|
22742
|
+
* place the file twice. */
|
|
22743
|
+
const onLandedRef = (0, react.useRef)(onLanded);
|
|
22744
|
+
onLandedRef.current = onLanded;
|
|
21782
22745
|
const selectionTextRef = (0, react.useRef)("");
|
|
21783
22746
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
21784
22747
|
const [searchOpen, setSearchOpen] = (0, react.useState)(false);
|
|
@@ -21794,12 +22757,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21794
22757
|
previewFlashPendingRef.current = true;
|
|
21795
22758
|
};
|
|
21796
22759
|
(0, react.useEffect)(() => {
|
|
21797
|
-
landingTopRef.current = landingTop;
|
|
21798
|
-
if (landingTop === void 0) {
|
|
21799
|
-
setFocus(0);
|
|
21800
|
-
bumpFlash(false);
|
|
21801
|
-
} else setFocus(blockIndexAtOffset(landingTop));
|
|
21802
|
-
setScrollTick((tick) => tick + 1);
|
|
21803
22760
|
bodyRef.current?.focus();
|
|
21804
22761
|
setHoveredBlock(void 0);
|
|
21805
22762
|
setSelection(void 0);
|
|
@@ -21809,10 +22766,44 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21809
22766
|
setSearchOpen(false);
|
|
21810
22767
|
setSearchQuery("");
|
|
21811
22768
|
setSearchIndex(0);
|
|
22769
|
+
}, [file.id]);
|
|
22770
|
+
const landedFileRef = (0, react.useRef)(void 0);
|
|
22771
|
+
/** The file the placement effect below has decided the opening place for (see `placedFileRef`). */
|
|
22772
|
+
const placedFileRef = (0, react.useRef)(void 0);
|
|
22773
|
+
(0, react.useEffect)(() => {
|
|
22774
|
+
const landing = (landingTick ?? 0) > 0;
|
|
22775
|
+
const opened = landedFileRef.current !== file.id;
|
|
22776
|
+
landedFileRef.current = file.id;
|
|
22777
|
+
placedFileRef.current = file.id;
|
|
22778
|
+
if (!landing && !opened) return;
|
|
22779
|
+
if (landing) {
|
|
22780
|
+
landingTopRef.current = landingTop;
|
|
22781
|
+
landingRowRef.current = landingRow;
|
|
22782
|
+
landingCardRef.current = landingCard === true;
|
|
22783
|
+
if (landingRow !== void 0) {
|
|
22784
|
+
setFocus(blockIndexAtOffset(offsetOf(landingRow)));
|
|
22785
|
+
bumpFlash(false);
|
|
22786
|
+
} else if (landingTop === void 0) {
|
|
22787
|
+
setFocus(0);
|
|
22788
|
+
bumpFlash(false);
|
|
22789
|
+
} else setFocus(blockIndexAtOffset(landingTop));
|
|
22790
|
+
setScrollTick((tick) => tick + 1);
|
|
22791
|
+
onLandedRef.current?.();
|
|
22792
|
+
return;
|
|
22793
|
+
}
|
|
22794
|
+
landingRowRef.current = void 0;
|
|
22795
|
+
landingCardRef.current = false;
|
|
22796
|
+
const offset = panelFileOffset(file.sessionId, file.id);
|
|
22797
|
+
if (offset === void 0) return;
|
|
22798
|
+
landingTopRef.current = offset;
|
|
22799
|
+
setFocus(blockIndexAtOffset(offset));
|
|
22800
|
+
setScrollTick((tick) => tick + 1);
|
|
21812
22801
|
}, [
|
|
21813
22802
|
file.id,
|
|
21814
22803
|
landingTop,
|
|
21815
|
-
landingTick
|
|
22804
|
+
landingTick,
|
|
22805
|
+
landingRow,
|
|
22806
|
+
landingCard
|
|
21816
22807
|
]);
|
|
21817
22808
|
(0, react.useEffect)(() => {
|
|
21818
22809
|
if (undoFlash === 0) return;
|
|
@@ -22331,11 +23322,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22331
23322
|
const wrapping = (widthPx ?? (bubble ? body * DISCUSSION_BUBBLE_MAX_WIDTH - 2 * DISCUSSION_BUBBLE_SIDE_PADDING_ROWS * THREAD_ROW_PX : body)) - measure("0");
|
|
22332
23323
|
if (wrapping <= 0) return lines.length + chrome;
|
|
22333
23324
|
const tabPx = tabWidthSpaces * measure(" ");
|
|
22334
|
-
|
|
22335
|
-
|
|
22336
|
-
|
|
22337
|
-
return rows + Math.max(1, wrapInto(line, room, measure, tabPx).length);
|
|
22338
|
-
}, 0);
|
|
23325
|
+
const chipMeasure = makeMeasurer(chipFontOf());
|
|
23326
|
+
const chipWidth = (text) => (chipMeasure === void 0 ? measure(text) : chipMeasure(text)) + 12;
|
|
23327
|
+
return chrome + lines.reduce((rows, line) => rows + Math.max(1, wrapChipRows(line, wrapping, measure, chipWidth, tabPx)), 0);
|
|
22339
23328
|
}, [
|
|
22340
23329
|
bodyWidth,
|
|
22341
23330
|
tabWidthSpaces,
|
|
@@ -22351,16 +23340,35 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22351
23340
|
* row per quoted line whatever the width.
|
|
22352
23341
|
* @returns the occupied row count (whole).
|
|
22353
23342
|
*/
|
|
22354
|
-
const quoteRowsOf = (0, react.useCallback)((quote, wrap) => {
|
|
22355
|
-
|
|
22356
|
-
|
|
23343
|
+
const quoteRowsOf = (0, react.useCallback)((quote, lines, wrap, split) => {
|
|
23344
|
+
const texts = quote.split("\n");
|
|
23345
|
+
if (!split) {
|
|
23346
|
+
if (!wrap) return texts.length;
|
|
23347
|
+
const measure = makeMeasurer(codeFontOf());
|
|
23348
|
+
const width = Math.max(0, bodyWidth - discussionRightInsetPx) - WRAP_GUTTERS_PX;
|
|
23349
|
+
if (measure === void 0) return texts.length;
|
|
23350
|
+
const wrapping = width - measure("0");
|
|
23351
|
+
if (wrapping <= 0) return texts.length;
|
|
23352
|
+
const tabPx = tabWidthSpaces * measure(" ");
|
|
23353
|
+
return texts.reduce((rows, line) => rows + Math.max(1, wrapInto(line, wrapping, measure, tabPx).length), 0);
|
|
23354
|
+
}
|
|
23355
|
+
const pairs = computeSideBySideDiff(texts.map((text, index) => {
|
|
23356
|
+
const line = lines?.[index];
|
|
23357
|
+
return {
|
|
23358
|
+
text,
|
|
23359
|
+
kind: line?.kind ?? "context",
|
|
23360
|
+
oldLine: line?.old,
|
|
23361
|
+
newLine: line?.new
|
|
23362
|
+
};
|
|
23363
|
+
}), true).pairs;
|
|
23364
|
+
if (!wrap) return pairs.length;
|
|
22357
23365
|
const measure = makeMeasurer(codeFontOf());
|
|
22358
|
-
|
|
22359
|
-
|
|
22360
|
-
|
|
22361
|
-
if (wrapping <= 0) return lines.length;
|
|
23366
|
+
if (measure === void 0) return pairs.length;
|
|
23367
|
+
const wrapping = Math.max(0, (bodyWidth - 1) / 2) - WRAP_GUTTERS_PX / 2 - measure("0");
|
|
23368
|
+
if (wrapping <= 0) return pairs.length;
|
|
22362
23369
|
const tabPx = tabWidthSpaces * measure(" ");
|
|
22363
|
-
|
|
23370
|
+
const rowsIn = (text) => text === void 0 ? 1 : Math.max(1, wrapInto(text, wrapping, measure, tabPx).length);
|
|
23371
|
+
return pairs.reduce((count, pair) => count + Math.max(rowsIn(pair.left?.text), rowsIn(pair.right?.text)), 0);
|
|
22364
23372
|
}, [
|
|
22365
23373
|
bodyWidth,
|
|
22366
23374
|
discussionRightInsetPx,
|
|
@@ -22377,7 +23385,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22377
23385
|
* @returns its size in code rows.
|
|
22378
23386
|
*/
|
|
22379
23387
|
const messageSizeOf = (0, react.useCallback)((message) => {
|
|
22380
|
-
return messageRowsOf(
|
|
23388
|
+
return messageRowsOf(discussionText(message), message.role);
|
|
22381
23389
|
}, [messageRowsOf]);
|
|
22382
23390
|
/**
|
|
22383
23391
|
* The thread as the block will render it, plus the body height that follows from
|
|
@@ -22389,13 +23397,27 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22389
23397
|
* @returns the messages to render, the hidden count, and the body height.
|
|
22390
23398
|
*/
|
|
22391
23399
|
const roundLimit = discussionRoundLimit();
|
|
23400
|
+
/**
|
|
23401
|
+
* Rows a thread's own rendered height corrected the model to, by thread id.
|
|
23402
|
+
*
|
|
23403
|
+
* The rows a block reserves are meant to BE the rows it draws, and the wrap model above is how
|
|
23404
|
+
* they are worked out — but a wrap model that is off by a row or by ten shows up as air under the
|
|
23405
|
+
* writing row (or as a clipped turn), and this one demonstrably is: the same answer has measured
|
|
23406
|
+
* 7, 11, 25 and 35 rows in different sessions at the same width. So the block's own rendered
|
|
23407
|
+
* height is read back after every render and the reservation is corrected to it — the same
|
|
23408
|
+
* "measure it, do not reason about it" rule the code view's wrapped rows follow. The map only
|
|
23409
|
+
* ever holds what was measured, and an entry stops changing once the drawing settles.
|
|
23410
|
+
*/
|
|
23411
|
+
const [rowFix, setRowFix] = (0, react.useState)({});
|
|
22392
23412
|
const layoutDiscussion = (0, react.useCallback)((discussion) => {
|
|
22393
23413
|
const answer = discussion.reply === void 0 ? void 0 : stripBlankLines(discussion.reply);
|
|
22394
23414
|
const stoppedNote = discussion.stopped === true && (answer === void 0 || answer === "") && discussion.failed !== true;
|
|
22395
|
-
const
|
|
23415
|
+
const outdatedRows = discussion.lost === true && discussion.quote !== void 0 && discussion.quote !== "" ? 1 + quoteRowsOf(discussion.quote, discussion.quoteLines, langWrap, splitView) * (ROW_HEIGHT_PX / THREAD_ROW_PX) : 0;
|
|
23416
|
+
const writingNote = discussion.asking === true && answer !== void 0 && answer !== "";
|
|
23417
|
+
const trailing = outdatedRows + (answer !== void 0 && answer !== "" ? messageSizeOf({
|
|
22396
23418
|
role: "assistant",
|
|
22397
23419
|
text: answer
|
|
22398
|
-
}) : discussion.failed === true || discussion.asking === true ? 1 : 2 + (stoppedNote ? 1 : 0));
|
|
23420
|
+
}) + (writingNote ? 1 : 0) : discussion.failed === true || discussion.asking === true ? 1 : 2 + (stoppedNote ? 1 : 0));
|
|
22399
23421
|
const tail = discussionRounds(discussion.messages, roundLimit, messageSizeOf);
|
|
22400
23422
|
return {
|
|
22401
23423
|
messages: tail.messages,
|
|
@@ -22407,7 +23429,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22407
23429
|
quoteRowsOf,
|
|
22408
23430
|
messageSizeOf,
|
|
22409
23431
|
roundLimit,
|
|
22410
|
-
ROW_HEIGHT_PX
|
|
23432
|
+
ROW_HEIGHT_PX,
|
|
23433
|
+
bodyWidth,
|
|
23434
|
+
splitView
|
|
22411
23435
|
]);
|
|
22412
23436
|
/**
|
|
22413
23437
|
* The discussions as the render will draw them: the body height the measurement
|
|
@@ -22420,15 +23444,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22420
23444
|
const laid = layoutDiscussion(discussion);
|
|
22421
23445
|
return {
|
|
22422
23446
|
...discussion,
|
|
22423
|
-
bodyRows: laid.rows,
|
|
23447
|
+
bodyRows: rowFix[discussion.id] ?? laid.rows,
|
|
22424
23448
|
hidden: laid.hidden,
|
|
23449
|
+
quoteWrap: langWrap,
|
|
22425
23450
|
messages: laid.messages.map((message) => ({
|
|
22426
23451
|
...message,
|
|
22427
23452
|
text: discussionText(message)
|
|
22428
23453
|
})),
|
|
22429
23454
|
...discussion.reply === void 0 ? {} : { reply: stripBlankLines(discussion.reply) }
|
|
22430
23455
|
};
|
|
22431
|
-
}), [
|
|
23456
|
+
}), [
|
|
23457
|
+
discussions,
|
|
23458
|
+
layoutDiscussion,
|
|
23459
|
+
rowFix
|
|
23460
|
+
]);
|
|
22432
23461
|
const discussionExtras = (0, react.useMemo)(() => discussionRowExtras(laidDiscussions, rows.length), [laidDiscussions, rows.length]);
|
|
22433
23462
|
const discussionsAtRow = (0, react.useMemo)(() => {
|
|
22434
23463
|
const byRow = /* @__PURE__ */ new Map();
|
|
@@ -22510,6 +23539,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22510
23539
|
(0, react.useEffect)(() => {
|
|
22511
23540
|
rememberDiscussions(file.sessionId, discussionsByFile);
|
|
22512
23541
|
}, [file.sessionId, discussionsByFile]);
|
|
23542
|
+
(0, react.useEffect)(() => {
|
|
23543
|
+
const changed = () => {
|
|
23544
|
+
const next = rememberedDiscussions(file.sessionId);
|
|
23545
|
+
setDiscussionsByFile((all) => all === next ? all : next);
|
|
23546
|
+
};
|
|
23547
|
+
window.addEventListener(COMMENTS_CHANGED_EVENT, changed);
|
|
23548
|
+
return () => {
|
|
23549
|
+
window.removeEventListener(COMMENTS_CHANGED_EVENT, changed);
|
|
23550
|
+
};
|
|
23551
|
+
}, [file.sessionId]);
|
|
22513
23552
|
/** Patch one discussion in place, without touching the others or the file key. */
|
|
22514
23553
|
const updateDiscussion = (0, react.useCallback)((id, patch) => {
|
|
22515
23554
|
setDiscussionsByFile((all) => {
|
|
@@ -22699,10 +23738,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22699
23738
|
(0, react.useEffect)(() => {
|
|
22700
23739
|
setDiscussionsByFile((all) => {
|
|
22701
23740
|
const list = all[file.id] ?? EMPTY_DISCUSSIONS;
|
|
22702
|
-
const next = list
|
|
23741
|
+
const next = remapDiscussions(list, (row) => {
|
|
22703
23742
|
const entry = model.diff.rows[row];
|
|
22704
23743
|
return entry?.newLine ?? entry?.oldLine;
|
|
22705
|
-
}, (row) => model.diff.rows[row]?.text ?? "", model.diff.rows.length));
|
|
23744
|
+
}, (row) => model.diff.rows[row]?.text ?? "", model.diff.rows.length, (row) => model.diff.rows[row]?.newLine !== void 0);
|
|
22706
23745
|
return next.some((discussion, index) => discussion !== list[index]) ? {
|
|
22707
23746
|
...all,
|
|
22708
23747
|
[file.id]: next
|
|
@@ -22756,32 +23795,35 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22756
23795
|
/** Start a discussion on the current selection (no-op on a range that has one). */
|
|
22757
23796
|
const addDiscussion = () => {
|
|
22758
23797
|
if (!commentMode) return;
|
|
22759
|
-
|
|
22760
|
-
if (
|
|
22761
|
-
|
|
22762
|
-
const
|
|
23798
|
+
const range = selectionRows(selection);
|
|
23799
|
+
if (range === void 0) return;
|
|
23800
|
+
if (discussionOverlapping(discussions, range) !== void 0) return;
|
|
23801
|
+
const first = model.diff.rows[range.start];
|
|
23802
|
+
const last = model.diff.rows[range.end] ?? first;
|
|
22763
23803
|
const startLine = first?.newLine ?? first?.oldLine;
|
|
22764
23804
|
if (startLine === void 0) return;
|
|
22765
23805
|
const endLine = last?.newLine ?? last?.oldLine ?? startLine;
|
|
22766
23806
|
const body = bodyRef.current;
|
|
22767
|
-
if (body !== null && offsetOf(
|
|
23807
|
+
if (body !== null && offsetOf(range.start) - body.scrollTop < 0) pendingScrollShiftRef.current += 66;
|
|
22768
23808
|
const id = `discussion-${Date.now().toString(36)}-${discussions.length}`;
|
|
22769
|
-
const quoted = model.diff.rows.slice(
|
|
23809
|
+
const quoted = model.diff.rows.slice(range.start, range.end + 1);
|
|
22770
23810
|
const quote = quoted.map((row) => row.text).join("\n");
|
|
22771
23811
|
const quoteLines = quoted.map((row) => ({
|
|
22772
23812
|
old: row.oldLine,
|
|
22773
23813
|
new: row.newLine,
|
|
22774
23814
|
kind: row.kind
|
|
22775
23815
|
}));
|
|
23816
|
+
const quoteContext = model.diff.rows.slice(Math.max(0, range.start - 1), Math.min(model.diff.rows.length, range.end + 2)).map((row) => row.text).join("\n");
|
|
22776
23817
|
setDiscussions((current) => [...current, {
|
|
22777
23818
|
id,
|
|
22778
23819
|
anchor: {
|
|
22779
|
-
start:
|
|
22780
|
-
end:
|
|
23820
|
+
start: range.start,
|
|
23821
|
+
end: range.end,
|
|
22781
23822
|
startLine,
|
|
22782
23823
|
endLine
|
|
22783
23824
|
},
|
|
22784
23825
|
quote,
|
|
23826
|
+
quoteContext,
|
|
22785
23827
|
quoteLines,
|
|
22786
23828
|
messages: [],
|
|
22787
23829
|
draft: "",
|
|
@@ -22832,6 +23874,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22832
23874
|
const sendDiscussion = (id) => {
|
|
22833
23875
|
const discussion = discussions.find((entry) => entry.id === id);
|
|
22834
23876
|
if (discussion === void 0) return;
|
|
23877
|
+
if (askingId !== void 0 && askingId !== id) return;
|
|
23878
|
+
if (pendingAskRef.current !== void 0 && pendingAskRef.current.id !== id) return;
|
|
22835
23879
|
const text = discussion.draft.trim();
|
|
22836
23880
|
if (text === "") return;
|
|
22837
23881
|
const reference = `(${discussionLineRange(discussion.anchor)})`;
|
|
@@ -22981,18 +24025,98 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22981
24025
|
previewActive,
|
|
22982
24026
|
splitView
|
|
22983
24027
|
]);
|
|
24028
|
+
const widthMovedRef = (0, react.useRef)(false);
|
|
24029
|
+
(0, react.useLayoutEffect)(() => {
|
|
24030
|
+
const body = bodyRef.current;
|
|
24031
|
+
if (body === null) return;
|
|
24032
|
+
const width = body.clientWidth;
|
|
24033
|
+
widthMovedRef.current = width !== bodyWidth;
|
|
24034
|
+
if (width !== bodyWidth) setBodyWidth(width);
|
|
24035
|
+
});
|
|
24036
|
+
const rowFixRef = (0, react.useRef)(rowFix);
|
|
24037
|
+
rowFixRef.current = rowFix;
|
|
24038
|
+
const fitWidthRef = (0, react.useRef)(0);
|
|
24039
|
+
const [, bumpFixTick] = (0, react.useReducer)((n) => n + 1, 0);
|
|
24040
|
+
const fixTickArmedRef = (0, react.useRef)(false);
|
|
24041
|
+
(0, react.useLayoutEffect)(() => {
|
|
24042
|
+
const cardWidth = document.querySelector("[data-diff-discussion]")?.getBoundingClientRect().width ?? 0;
|
|
24043
|
+
const settled = cardWidth > 0 && Math.abs(cardWidth - fitWidthRef.current) <= 1;
|
|
24044
|
+
fitWidthRef.current = cardWidth;
|
|
24045
|
+
if (!settled) {
|
|
24046
|
+
if (cardWidth > 0 && !widthMovedRef.current && !fixTickArmedRef.current) {
|
|
24047
|
+
const armed = bodyRef.current?.clientWidth ?? 0;
|
|
24048
|
+
fixTickArmedRef.current = true;
|
|
24049
|
+
requestAnimationFrame(() => {
|
|
24050
|
+
fixTickArmedRef.current = false;
|
|
24051
|
+
if ((bodyRef.current?.clientWidth ?? 0) !== armed) return;
|
|
24052
|
+
bumpFixTick();
|
|
24053
|
+
});
|
|
24054
|
+
}
|
|
24055
|
+
return;
|
|
24056
|
+
}
|
|
24057
|
+
const next = { ...rowFixRef.current };
|
|
24058
|
+
let changed = false;
|
|
24059
|
+
for (const card of document.querySelectorAll("[data-diff-discussion]")) {
|
|
24060
|
+
const id = card.dataset.diffDiscussionId;
|
|
24061
|
+
const body = card.children[1];
|
|
24062
|
+
const last = body?.lastElementChild;
|
|
24063
|
+
if (id === void 0 || body === void 0 || last === null || last === void 0) continue;
|
|
24064
|
+
const drawn = last.getBoundingClientRect().bottom + (Number.parseFloat(getComputedStyle(last).marginBottom) || 0) - body.getBoundingClientRect().top;
|
|
24065
|
+
if (drawn <= 0) continue;
|
|
24066
|
+
const want = Math.max(1, Math.ceil(drawn / THREAD_ROW_PX));
|
|
24067
|
+
if (next[id] !== want) {
|
|
24068
|
+
next[id] = want;
|
|
24069
|
+
changed = true;
|
|
24070
|
+
}
|
|
24071
|
+
}
|
|
24072
|
+
if (changed) setRowFix(next);
|
|
24073
|
+
});
|
|
24074
|
+
/**
|
|
24075
|
+
* Move the code view to one offset, and take the page's memory with it.
|
|
24076
|
+
*
|
|
24077
|
+
* The memory is what a pane that remounts under the reader resumes (see the landing effect), so it
|
|
24078
|
+
* has to follow every write the panel itself makes — a jump included. Mirroring only the reader's
|
|
24079
|
+
* own scrolls would leave a remount resuming the place they left rather than the place the jump
|
|
24080
|
+
* put them, which is the same "it moved on its own" the memory exists to stop.
|
|
24081
|
+
*
|
|
24082
|
+
* @param body - the code view's scroll box.
|
|
24083
|
+
* @param offset - the offset to settle it at.
|
|
24084
|
+
*/
|
|
24085
|
+
const applyScrollTop = (body, offset) => {
|
|
24086
|
+
if (body.scrollTop !== offset) body.scrollTop = offset;
|
|
24087
|
+
setScrollTop(offset);
|
|
24088
|
+
rememberPanelView(file.sessionId, {
|
|
24089
|
+
fileId: file.id,
|
|
24090
|
+
scrollTop: offset
|
|
24091
|
+
});
|
|
24092
|
+
};
|
|
22984
24093
|
(0, react.useLayoutEffect)(() => {
|
|
22985
24094
|
if (rowCount === 0) return;
|
|
24095
|
+
if (placedFileRef.current !== file.id) return;
|
|
22986
24096
|
const resumed = landingTopRef.current;
|
|
22987
24097
|
if (resumed !== void 0) {
|
|
22988
24098
|
landingTopRef.current = void 0;
|
|
22989
24099
|
if (!previewActive) {
|
|
22990
24100
|
const resumeBody = bodyRef.current;
|
|
22991
|
-
if (resumeBody !== null)
|
|
22992
|
-
|
|
22993
|
-
|
|
22994
|
-
|
|
22995
|
-
|
|
24101
|
+
if (resumeBody !== null) applyScrollTop(resumeBody, Math.max(0, Math.min(resumed, resumeBody.scrollHeight - resumeBody.clientHeight)));
|
|
24102
|
+
}
|
|
24103
|
+
return;
|
|
24104
|
+
}
|
|
24105
|
+
const row = landingRowRef.current;
|
|
24106
|
+
if (row !== void 0 && !previewActive) {
|
|
24107
|
+
const toCard = landingCardRef.current;
|
|
24108
|
+
landingRowRef.current = void 0;
|
|
24109
|
+
landingCardRef.current = false;
|
|
24110
|
+
flashRowRef.current = void 0;
|
|
24111
|
+
if (splitView) {
|
|
24112
|
+
splitDiffRef.current?.land(row, toCard);
|
|
24113
|
+
return;
|
|
24114
|
+
}
|
|
24115
|
+
const rowBody = bodyRef.current;
|
|
24116
|
+
if (rowBody !== null) {
|
|
24117
|
+
const cardTop = offsetOf(row + 1) - (discussionExtras.get(row) ?? 0) * THREAD_ROW_PX;
|
|
24118
|
+
const target = toCard ? cardTop : offsetOf(row);
|
|
24119
|
+
applyScrollTop(rowBody, Math.max(0, Math.min(target - leadRows * ROW_HEIGHT_PX, rowBody.scrollHeight - rowBody.clientHeight)));
|
|
22996
24120
|
}
|
|
22997
24121
|
return;
|
|
22998
24122
|
}
|
|
@@ -23009,9 +24133,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23009
24133
|
const body = bodyRef.current;
|
|
23010
24134
|
if (body === null) return;
|
|
23011
24135
|
const target = offsetOf(block.start) - leadRows * ROW_HEIGHT_PX;
|
|
23012
|
-
|
|
23013
|
-
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
23014
|
-
setScrollTop(clamped);
|
|
24136
|
+
applyScrollTop(body, Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight)));
|
|
23015
24137
|
}, [
|
|
23016
24138
|
scrollTick,
|
|
23017
24139
|
offsetsFromWrap,
|
|
@@ -23059,6 +24181,43 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23059
24181
|
};
|
|
23060
24182
|
const jumpBlockRef = (0, react.useRef)(jumpBlock);
|
|
23061
24183
|
jumpBlockRef.current = jumpBlock;
|
|
24184
|
+
/**
|
|
24185
|
+
* Go to a line of the file as it reads NOW: the row carrying that new-file line, because the old side
|
|
24186
|
+
* of the diff is not a place a reader can be sent (its numbers belong to text that is already gone) —
|
|
24187
|
+
* a number that only exists there is answered with a note instead. Both views take it the way a comment
|
|
24188
|
+
* jump does: the split view through its own handle, one column through the height table, with the
|
|
24189
|
+
* configured lead rows above it and the block it lands in flashed.
|
|
24190
|
+
*/
|
|
24191
|
+
const gotoLine = (line) => {
|
|
24192
|
+
const row = model.diff.rows.findIndex((entry) => entry.newLine === line);
|
|
24193
|
+
if (row === -1) {
|
|
24194
|
+
onToast(t("panel.gotoMissing", { line }));
|
|
24195
|
+
return;
|
|
24196
|
+
}
|
|
24197
|
+
if (splitView && !previewActive) {
|
|
24198
|
+
splitDiffRef.current?.land(row, false, true);
|
|
24199
|
+
return;
|
|
24200
|
+
}
|
|
24201
|
+
bumpFlash(false);
|
|
24202
|
+
flashRowRef.current = row;
|
|
24203
|
+
setFocus(blockIndexAtOffset(offsetOf(row)));
|
|
24204
|
+
const body = bodyRef.current;
|
|
24205
|
+
if (body === null) return;
|
|
24206
|
+
applyScrollTop(body, Math.max(0, Math.min(offsetOf(row) - leadRows * ROW_HEIGHT_PX, body.scrollHeight - body.clientHeight)));
|
|
24207
|
+
};
|
|
24208
|
+
(0, react.useEffect)(() => {
|
|
24209
|
+
const onKeyDown = (event) => {
|
|
24210
|
+
if (!matchesShortcut(event, keybindingOf("goto"))) return;
|
|
24211
|
+
if (isTextFieldEvent(event) || pathPickerOpen()) return;
|
|
24212
|
+
event.preventDefault();
|
|
24213
|
+
setGotoDraft("");
|
|
24214
|
+
setGotoOpen(true);
|
|
24215
|
+
};
|
|
24216
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
24217
|
+
return () => {
|
|
24218
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
24219
|
+
};
|
|
24220
|
+
}, []);
|
|
23062
24221
|
const stepBlock = (direction) => {
|
|
23063
24222
|
const count = model.blocks.length;
|
|
23064
24223
|
if (count === 0) return;
|
|
@@ -23122,6 +24281,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23122
24281
|
const body = bodyRef.current;
|
|
23123
24282
|
if (body === null) return;
|
|
23124
24283
|
syncQuoteScroll(body);
|
|
24284
|
+
rememberPanelView(file.sessionId, {
|
|
24285
|
+
fileId: file.id,
|
|
24286
|
+
scrollTop: body.scrollTop
|
|
24287
|
+
});
|
|
23125
24288
|
setScrollTop(body.scrollTop);
|
|
23126
24289
|
setViewportHeight(body.clientHeight);
|
|
23127
24290
|
const count = model.blocks.length;
|
|
@@ -23248,9 +24411,59 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23248
24411
|
window.removeEventListener(COMMENT_MODE_CHANGED_EVENT, onCommentMode);
|
|
23249
24412
|
};
|
|
23250
24413
|
}, []);
|
|
23251
|
-
|
|
23252
|
-
|
|
23253
|
-
|
|
24414
|
+
/**
|
|
24415
|
+
* One thread's card, as every view draws it. The views differ only in where the card hangs and
|
|
24416
|
+
* how wide the thing it hangs in is, so the card itself is built in exactly one place (see
|
|
24417
|
+
* `DiscussionBlock`): the single-column row stream, and whatever view comes next.
|
|
24418
|
+
*/
|
|
24419
|
+
const renderDiscussion = (0, react.useCallback)((discussion, width, split) => (0, react_jsx_runtime.jsx)(DiscussionBlock, {
|
|
24420
|
+
discussion,
|
|
24421
|
+
label: discussionLineRange(discussion.anchor),
|
|
24422
|
+
bodyWidth: width,
|
|
24423
|
+
lang,
|
|
24424
|
+
menuOpen: discussionMenuFor === discussion.id,
|
|
24425
|
+
asking: askingId !== void 0,
|
|
24426
|
+
split,
|
|
24427
|
+
t,
|
|
24428
|
+
onToggle: toggleDiscussion,
|
|
24429
|
+
onMenuOpen: setDiscussionMenuFor,
|
|
24430
|
+
onRemove: removeDiscussion,
|
|
24431
|
+
onDraft: (id, value) => {
|
|
24432
|
+
setDiscussions((current) => current.map((entry) => entry.id === id ? {
|
|
24433
|
+
...entry,
|
|
24434
|
+
draft: value
|
|
24435
|
+
} : entry));
|
|
24436
|
+
},
|
|
24437
|
+
onSend: sendDiscussion,
|
|
24438
|
+
registerInput: (id, element) => {
|
|
24439
|
+
if (element === null) discussionInputEls.current.delete(id);
|
|
24440
|
+
else discussionInputEls.current.set(id, element);
|
|
24441
|
+
}
|
|
24442
|
+
}), [
|
|
24443
|
+
discussionMenuFor,
|
|
24444
|
+
askingId,
|
|
24445
|
+
t,
|
|
24446
|
+
lang,
|
|
24447
|
+
toggleDiscussion,
|
|
24448
|
+
removeDiscussion,
|
|
24449
|
+
sendDiscussion,
|
|
24450
|
+
discussionLineRange
|
|
24451
|
+
]);
|
|
24452
|
+
/**
|
|
24453
|
+
* The lines a selection names, whichever view made it, or undefined when it names none this panel
|
|
24454
|
+
* can comment on — a side-by-side selection of the LEFT column is the old file, and a thread is
|
|
24455
|
+
* anchored to new-file lines. The frame (and the chord) hang off this, so the left column simply
|
|
24456
|
+
* offers nothing.
|
|
24457
|
+
*/
|
|
24458
|
+
const selectionRowRange = selectionRows(selection);
|
|
24459
|
+
/**
|
|
24460
|
+
* Whether those lines already carry a thread: the comment is withheld then (a row belongs to one
|
|
24461
|
+
* annotation at most).
|
|
24462
|
+
*/
|
|
24463
|
+
const selectionHasDiscussion = selectionRowRange !== void 0 && discussionOverlapping(discussions, selectionRowRange) !== void 0;
|
|
24464
|
+
const frameForSelection = selectionRowRange !== void 0 ? selectionFrame({
|
|
24465
|
+
coversBlocks: !splitView && selectionRange !== void 0,
|
|
24466
|
+
hasDiscussion: selectionHasDiscussion
|
|
23254
24467
|
}) : void 0;
|
|
23255
24468
|
const selectionCommentOffered = commentMode && frameForSelection?.comment === true;
|
|
23256
24469
|
const selectionFrameVisible = frameForSelection !== void 0 && (frameForSelection.keepRevert || selectionCommentOffered);
|
|
@@ -23383,8 +24596,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23383
24596
|
const scrollbarWidth = scroller.offsetWidth - scroller.clientWidth;
|
|
23384
24597
|
return Math.max(0, scroller.clientWidth - (scrollbarWidth > 0 ? 0 : OVERVIEW_RULER_WIDTH_PX));
|
|
23385
24598
|
})();
|
|
23386
|
-
const
|
|
23387
|
-
const
|
|
24599
|
+
const flashRow = flashRowRef.current;
|
|
24600
|
+
const flashTop = flashRow !== void 0 ? Math.max(0, offsetOf(flashRow) - scrollTop) : focusedBlock === void 0 ? 0 : Math.max(0, offsetOf(focusedBlock.start) - scrollTop);
|
|
24601
|
+
const flashBottom = flashRow !== void 0 ? Math.min(viewportHeight > 0 ? viewportHeight : Number.POSITIVE_INFINITY, offsetOf(flashRow + 1) - scrollTop) : focusedBlock === void 0 ? 0 : Math.min(viewportHeight > 0 ? viewportHeight : Number.POSITIVE_INFINITY, offsetOf(focusedBlock.end + 1) - scrollTop);
|
|
23388
24602
|
const flashHeight = Math.max(0, flashBottom - flashTop);
|
|
23389
24603
|
const previewFlashNow = previewActive ? previewFlashBox(previewFlash, previewScrollTopRef.current) : void 0;
|
|
23390
24604
|
const searchBar = searchOpen ? (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -23667,6 +24881,110 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23667
24881
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, { size: 14 })
|
|
23668
24882
|
})
|
|
23669
24883
|
}),
|
|
24884
|
+
previewActive ? null : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
24885
|
+
label: withChord(t("action.goto"), "goto"),
|
|
24886
|
+
side: "bottom",
|
|
24887
|
+
delayMs: 500,
|
|
24888
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
24889
|
+
type: "button",
|
|
24890
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
24891
|
+
"data-diff-goto": true,
|
|
24892
|
+
"aria-label": t("action.goto"),
|
|
24893
|
+
onClick: () => {
|
|
24894
|
+
setGotoDraft("");
|
|
24895
|
+
setGotoOpen(true);
|
|
24896
|
+
},
|
|
24897
|
+
children: (0, react_jsx_runtime.jsx)(GotoLineIcon, {})
|
|
24898
|
+
})
|
|
24899
|
+
}),
|
|
24900
|
+
gotoOpen && (0, react_jsx_runtime.jsx)("div", {
|
|
24901
|
+
role: "dialog",
|
|
24902
|
+
"aria-label": t("action.goto"),
|
|
24903
|
+
"data-diff-goto-dialog": true,
|
|
24904
|
+
style: {
|
|
24905
|
+
position: "fixed",
|
|
24906
|
+
inset: 0,
|
|
24907
|
+
zIndex: 40,
|
|
24908
|
+
display: "grid",
|
|
24909
|
+
placeItems: "center",
|
|
24910
|
+
background: "rgba(0, 0, 0, 0.18)"
|
|
24911
|
+
},
|
|
24912
|
+
onClick: () => {
|
|
24913
|
+
setGotoOpen(false);
|
|
24914
|
+
},
|
|
24915
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
24916
|
+
className: PendingPanel_module_css_default.gotoBox,
|
|
24917
|
+
style: {
|
|
24918
|
+
display: "flex",
|
|
24919
|
+
gap: 8,
|
|
24920
|
+
alignItems: "center",
|
|
24921
|
+
padding: 12,
|
|
24922
|
+
borderRadius: 12,
|
|
24923
|
+
background: "var(--dsw-alias-bg-base)",
|
|
24924
|
+
boxShadow: "var(--dsw-shadow-lv2)"
|
|
24925
|
+
},
|
|
24926
|
+
onClick: (event) => {
|
|
24927
|
+
event.stopPropagation();
|
|
24928
|
+
},
|
|
24929
|
+
children: [
|
|
24930
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
24931
|
+
className: PendingPanel_module_css_default.gotoInput,
|
|
24932
|
+
"data-diff-goto-input": true,
|
|
24933
|
+
value: gotoDraft,
|
|
24934
|
+
autoFocus: true,
|
|
24935
|
+
inputMode: "numeric",
|
|
24936
|
+
spellCheck: false,
|
|
24937
|
+
autoComplete: "off",
|
|
24938
|
+
"aria-label": t("action.goto"),
|
|
24939
|
+
placeholder: t("action.goto"),
|
|
24940
|
+
style: {
|
|
24941
|
+
width: "8em",
|
|
24942
|
+
padding: "4px 8px",
|
|
24943
|
+
borderRadius: 8,
|
|
24944
|
+
border: "1px solid var(--dsw-alias-border-l2)",
|
|
24945
|
+
background: "transparent",
|
|
24946
|
+
color: "inherit",
|
|
24947
|
+
font: "inherit"
|
|
24948
|
+
},
|
|
24949
|
+
onChange: (event) => {
|
|
24950
|
+
setGotoDraft(event.target.value);
|
|
24951
|
+
},
|
|
24952
|
+
onKeyDown: (event) => {
|
|
24953
|
+
if (event.key === "Escape") {
|
|
24954
|
+
event.preventDefault();
|
|
24955
|
+
setGotoOpen(false);
|
|
24956
|
+
return;
|
|
24957
|
+
}
|
|
24958
|
+
if (event.key !== "Enter") return;
|
|
24959
|
+
event.preventDefault();
|
|
24960
|
+
const line = Number.parseInt(gotoDraft.trim(), 10);
|
|
24961
|
+
setGotoOpen(false);
|
|
24962
|
+
if (Number.isFinite(line) && line > 0) gotoLine(line);
|
|
24963
|
+
}
|
|
24964
|
+
}),
|
|
24965
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
24966
|
+
type: "button",
|
|
24967
|
+
className: PendingPanel_module_css_default.action,
|
|
24968
|
+
"data-diff-goto-go": true,
|
|
24969
|
+
onClick: () => {
|
|
24970
|
+
const line = Number.parseInt(gotoDraft.trim(), 10);
|
|
24971
|
+
setGotoOpen(false);
|
|
24972
|
+
if (Number.isFinite(line) && line > 0) gotoLine(line);
|
|
24973
|
+
},
|
|
24974
|
+
children: t("action.gotoGo")
|
|
24975
|
+
}),
|
|
24976
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
24977
|
+
type: "button",
|
|
24978
|
+
className: PendingPanel_module_css_default.action,
|
|
24979
|
+
"data-diff-goto-cancel": true,
|
|
24980
|
+
onClick: () => {
|
|
24981
|
+
setGotoOpen(false);
|
|
24982
|
+
},
|
|
24983
|
+
children: t("action.gotoCancel")
|
|
24984
|
+
})
|
|
24985
|
+
]
|
|
24986
|
+
})
|
|
24987
|
+
}),
|
|
23670
24988
|
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.divider }),
|
|
23671
24989
|
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
23672
24990
|
label: t(splitView ? "action.viewUnified" : "action.viewSplit"),
|
|
@@ -23917,7 +25235,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23917
25235
|
onBlockKeep,
|
|
23918
25236
|
onBlockRevert,
|
|
23919
25237
|
onWrapToast: (text) => onToast(text),
|
|
23920
|
-
onVisibleLines: onSplitVisibleLines
|
|
25238
|
+
onVisibleLines: onSplitVisibleLines,
|
|
25239
|
+
discussions: laidDiscussions,
|
|
25240
|
+
renderDiscussion,
|
|
25241
|
+
selectionComment: splitView && selectionCommentOffered ? (0, react_jsx_runtime.jsxs)("button", {
|
|
25242
|
+
type: "button",
|
|
25243
|
+
className: PendingPanel_module_css_default.action,
|
|
25244
|
+
"data-diff-selection-comment": true,
|
|
25245
|
+
onClick: addDiscussion,
|
|
25246
|
+
children: [t("action.comment"), commentChord !== "" && (0, react_jsx_runtime.jsx)("span", {
|
|
25247
|
+
className: PendingPanel_module_css_default.actionChord,
|
|
25248
|
+
"data-diff-selection-comment-chord": true,
|
|
25249
|
+
children: commentChord
|
|
25250
|
+
})]
|
|
25251
|
+
}) : void 0
|
|
23921
25252
|
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
23922
25253
|
className: PendingPanel_module_css_default.diffBodyWrap,
|
|
23923
25254
|
ref: bodyWrapRef,
|
|
@@ -23982,156 +25313,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23982
25313
|
children: (0, react_jsx_runtime.jsx)("div", {
|
|
23983
25314
|
className: PendingPanel_module_css_default.discussionPin,
|
|
23984
25315
|
style: { marginLeft: -88 },
|
|
23985
|
-
children: (
|
|
23986
|
-
className: PendingPanel_module_css_default.discussion,
|
|
23987
|
-
"data-diff-discussion": true,
|
|
23988
|
-
"data-lost": discussion.lost === true ? "" : void 0,
|
|
23989
|
-
style: {
|
|
23990
|
-
width: Math.max(0, bodyWidth - discussionRightInsetPx),
|
|
23991
|
-
height: rows * THREAD_ROW_PX
|
|
23992
|
-
},
|
|
23993
|
-
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
23994
|
-
className: PendingPanel_module_css_default.discussionHead,
|
|
23995
|
-
children: [
|
|
23996
|
-
(0, react_jsx_runtime.jsx)("button", {
|
|
23997
|
-
type: "button",
|
|
23998
|
-
className: PendingPanel_module_css_default.discussionToggle,
|
|
23999
|
-
"data-diff-discussion-toggle": true,
|
|
24000
|
-
"aria-expanded": !discussion.collapsed,
|
|
24001
|
-
"aria-label": t(discussion.collapsed ? "action.discussionExpand" : "action.discussionCollapse"),
|
|
24002
|
-
onClick: () => {
|
|
24003
|
-
toggleDiscussion(discussion.id);
|
|
24004
|
-
},
|
|
24005
|
-
children: discussion.collapsed ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 12 }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 12 })
|
|
24006
|
-
}),
|
|
24007
|
-
(0, react_jsx_runtime.jsxs)("span", {
|
|
24008
|
-
className: PendingPanel_module_css_default.discussionRangeWrap,
|
|
24009
|
-
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
24010
|
-
className: PendingPanel_module_css_default.discussionRange,
|
|
24011
|
-
"data-diff-discussion-range": true,
|
|
24012
|
-
children: discussionLineRange(discussion.anchor)
|
|
24013
|
-
}), discussion.lost === true && (0, react_jsx_runtime.jsx)("span", {
|
|
24014
|
-
className: PendingPanel_module_css_default.discussionOutdated,
|
|
24015
|
-
"data-diff-discussion-outdated": true,
|
|
24016
|
-
children: t("discussion.outdated")
|
|
24017
|
-
})]
|
|
24018
|
-
}),
|
|
24019
|
-
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
|
|
24020
|
-
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
24021
|
-
open: discussionMenuFor === discussion.id,
|
|
24022
|
-
portal: true,
|
|
24023
|
-
compact: true,
|
|
24024
|
-
align: "end",
|
|
24025
|
-
items: discussionMenuItems,
|
|
24026
|
-
onSelect: (id) => {
|
|
24027
|
-
if (id === "delete") removeDiscussion(discussion.id);
|
|
24028
|
-
setDiscussionMenuFor(void 0);
|
|
24029
|
-
},
|
|
24030
|
-
onClose: () => {
|
|
24031
|
-
setDiscussionMenuFor(void 0);
|
|
24032
|
-
},
|
|
24033
|
-
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
24034
|
-
type: "button",
|
|
24035
|
-
className: PendingPanel_module_css_default.discussionToggle,
|
|
24036
|
-
"data-diff-discussion-menu": true,
|
|
24037
|
-
"aria-label": t("action.more"),
|
|
24038
|
-
onClick: () => {
|
|
24039
|
-
setDiscussionMenuFor((current) => current === discussion.id ? void 0 : discussion.id);
|
|
24040
|
-
},
|
|
24041
|
-
children: "⋯"
|
|
24042
|
-
})
|
|
24043
|
-
})
|
|
24044
|
-
]
|
|
24045
|
-
}), !discussion.collapsed && (0, react_jsx_runtime.jsxs)("div", {
|
|
24046
|
-
className: PendingPanel_module_css_default.discussionBody,
|
|
24047
|
-
children: [
|
|
24048
|
-
discussion.lost === true && discussion.quote !== void 0 && discussion.quote !== "" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("p", {
|
|
24049
|
-
className: PendingPanel_module_css_default.discussionNote,
|
|
24050
|
-
"data-diff-discussion-quote-label": true,
|
|
24051
|
-
children: t("discussion.quote")
|
|
24052
|
-
}), (0, react_jsx_runtime.jsx)(DiscussionQuote, {
|
|
24053
|
-
quote: discussion.quote,
|
|
24054
|
-
lines: discussion.quoteLines,
|
|
24055
|
-
lang,
|
|
24056
|
-
wrap: langWrap
|
|
24057
|
-
})] }),
|
|
24058
|
-
discussion.hidden !== void 0 && discussion.hidden > 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
24059
|
-
className: PendingPanel_module_css_default.discussionNote,
|
|
24060
|
-
"data-diff-discussion-hidden": true,
|
|
24061
|
-
children: t("discussion.hidden", { count: discussion.hidden })
|
|
24062
|
-
}),
|
|
24063
|
-
discussion.stopped === true && (discussion.reply === void 0 || discussion.reply === "") && discussion.failed !== true && (0, react_jsx_runtime.jsx)("p", {
|
|
24064
|
-
className: PendingPanel_module_css_default.discussionNote,
|
|
24065
|
-
"data-diff-discussion-stopped": true,
|
|
24066
|
-
children: t("discussion.stopped")
|
|
24067
|
-
}),
|
|
24068
|
-
discussion.messages.map((message, index) => message.role === "user" ? (0, react_jsx_runtime.jsx)("p", {
|
|
24069
|
-
className: PendingPanel_module_css_default.discussionUser,
|
|
24070
|
-
"data-diff-discussion-user": true,
|
|
24071
|
-
children: discussionNodes(message.text)
|
|
24072
|
-
}, `u${index}`) : (0, react_jsx_runtime.jsx)("p", {
|
|
24073
|
-
className: PendingPanel_module_css_default.discussionAnswer,
|
|
24074
|
-
"data-diff-discussion-reply": true,
|
|
24075
|
-
children: discussionNodes(message.text)
|
|
24076
|
-
}, `a${index}`)),
|
|
24077
|
-
discussion.reply !== void 0 && discussion.reply !== "" ? (0, react_jsx_runtime.jsx)("p", {
|
|
24078
|
-
className: PendingPanel_module_css_default.discussionAnswer,
|
|
24079
|
-
"data-diff-discussion-reply": true,
|
|
24080
|
-
children: discussionNodes(discussion.reply)
|
|
24081
|
-
}) : discussion.failed === true ? (0, react_jsx_runtime.jsx)("p", {
|
|
24082
|
-
className: PendingPanel_module_css_default.discussionNote,
|
|
24083
|
-
"data-diff-discussion-failed": true,
|
|
24084
|
-
children: t("discussion.failed")
|
|
24085
|
-
}) : discussion.asking === true ? (0, react_jsx_runtime.jsxs)("p", {
|
|
24086
|
-
className: PendingPanel_module_css_default.discussionNote,
|
|
24087
|
-
"data-diff-discussion-asking": true,
|
|
24088
|
-
children: [discussion.queued === true ? t("discussion.queued") : t("discussion.thinking"), (0, react_jsx_runtime.jsxs)("span", {
|
|
24089
|
-
className: PendingPanel_module_css_default.discussionDots,
|
|
24090
|
-
"data-diff-discussion-dots": true,
|
|
24091
|
-
"aria-hidden": "true",
|
|
24092
|
-
children: [
|
|
24093
|
-
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
24094
|
-
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
24095
|
-
(0, react_jsx_runtime.jsx)("span", { children: "." })
|
|
24096
|
-
]
|
|
24097
|
-
})]
|
|
24098
|
-
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
24099
|
-
className: PendingPanel_module_css_default.discussionCompose,
|
|
24100
|
-
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
24101
|
-
className: PendingPanel_module_css_default.discussionInput,
|
|
24102
|
-
"data-diff-discussion-input": true,
|
|
24103
|
-
ref: (element) => {
|
|
24104
|
-
if (element === null) discussionInputEls.current.delete(discussion.id);
|
|
24105
|
-
else discussionInputEls.current.set(discussion.id, element);
|
|
24106
|
-
},
|
|
24107
|
-
value: discussion.draft,
|
|
24108
|
-
placeholder: t("discussion.placeholder"),
|
|
24109
|
-
onChange: (event) => {
|
|
24110
|
-
const value = event.target.value;
|
|
24111
|
-
setDiscussions((current) => current.map((entry) => entry.id === discussion.id ? {
|
|
24112
|
-
...entry,
|
|
24113
|
-
draft: value
|
|
24114
|
-
} : entry));
|
|
24115
|
-
},
|
|
24116
|
-
onKeyDown: (event) => {
|
|
24117
|
-
if (event.key !== "Enter") return;
|
|
24118
|
-
if (event.nativeEvent.isComposing || event.keyCode === 229) return;
|
|
24119
|
-
event.preventDefault();
|
|
24120
|
-
sendDiscussion(discussion.id);
|
|
24121
|
-
}
|
|
24122
|
-
}), (0, react_jsx_runtime.jsxs)("button", {
|
|
24123
|
-
type: "button",
|
|
24124
|
-
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary} ${PendingPanel_module_css_default.discussionSend}`,
|
|
24125
|
-
"data-diff-discussion-send": true,
|
|
24126
|
-
onClick: () => {
|
|
24127
|
-
sendDiscussion(discussion.id);
|
|
24128
|
-
},
|
|
24129
|
-
children: [t("action.comment"), (0, react_jsx_runtime.jsx)(ReturnIcon, {})]
|
|
24130
|
-
})]
|
|
24131
|
-
})
|
|
24132
|
-
]
|
|
24133
|
-
})]
|
|
24134
|
-
}, discussion.id)
|
|
25316
|
+
children: renderDiscussion(discussion, bodyWidth, false)
|
|
24135
25317
|
})
|
|
24136
25318
|
})
|
|
24137
25319
|
]
|
|
@@ -24423,13 +25605,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24423
25605
|
* that lands on the file's first change.
|
|
24424
25606
|
*/
|
|
24425
25607
|
const [landing, setLanding] = (0, react.useState)(void 0);
|
|
24426
|
-
/** Ask the diff to land on one file: its first change unless `top` says where
|
|
25608
|
+
/** Ask the diff to land on one file: its first change unless `top` says where, or the row a jump
|
|
25609
|
+
* to a comment names (which lands the way a change-block jump does, see `landingRow`). `card` lands
|
|
25610
|
+
* the thread's own box instead of the rows it named, which is what an outdated comment needs: the
|
|
25611
|
+
* code it was written about is gone, so the position its numbers point at says nothing.
|
|
24427
25612
|
* The nonce makes the request an event rather than a value, so re-clicking the
|
|
24428
25613
|
* chip for the file already open lands on its first change again. */
|
|
24429
|
-
const landOn = (fileId, top) => {
|
|
25614
|
+
const landOn = (fileId, top, row, card) => {
|
|
24430
25615
|
setLanding((prev) => ({
|
|
24431
25616
|
fileId,
|
|
24432
25617
|
top,
|
|
25618
|
+
row,
|
|
25619
|
+
card,
|
|
24433
25620
|
n: (prev?.n ?? 0) + 1
|
|
24434
25621
|
}));
|
|
24435
25622
|
};
|
|
@@ -24437,6 +25624,44 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24437
25624
|
* cleanup (the docked tab unmounting) rather than from a handler. */
|
|
24438
25625
|
const selectedRef = (0, react.useRef)(selected);
|
|
24439
25626
|
selectedRef.current = selected;
|
|
25627
|
+
/**
|
|
25628
|
+
* Which tab the list pane shows: the pending files, or every comment the files in the list carry.
|
|
25629
|
+
* The pane's own state rather than a remembered preference: a reader who came to the list for a
|
|
25630
|
+
* comment is in the comments tab while they read it, and the next time the panel opens it is the
|
|
25631
|
+
* list they are shown — the pending list is what the panel is for.
|
|
25632
|
+
*/
|
|
25633
|
+
const [listTab, setListTab] = (0, react.useState)("pending");
|
|
25634
|
+
/**
|
|
25635
|
+
* Whether this panel is commenting at all: with comment mode off there are no comments to list, so
|
|
25636
|
+
* the pane is the pending list alone and shows no tabs. It follows the setting like the frame does
|
|
25637
|
+
* (the Settings section is another mount).
|
|
25638
|
+
*/
|
|
25639
|
+
const [commentMode, setCommentMode] = (0, react.useState)(commentModeEnabled);
|
|
25640
|
+
/** The tabs the pane offers: the comments one exists only while the panel is commenting, so with
|
|
25641
|
+
* the mode off the pane has one view and no switch to offer. */
|
|
25642
|
+
const listTabs = commentMode ? ["pending", "comments"] : ["pending"];
|
|
25643
|
+
/** The tab actually shown: the comments one only exists while the mode is on. */
|
|
25644
|
+
const activeTab = commentMode ? listTab : "pending";
|
|
25645
|
+
(0, react.useEffect)(() => {
|
|
25646
|
+
const onCommentMode = () => {
|
|
25647
|
+
setCommentMode(commentModeEnabled());
|
|
25648
|
+
};
|
|
25649
|
+
window.addEventListener(COMMENT_MODE_CHANGED_EVENT, onCommentMode);
|
|
25650
|
+
return () => {
|
|
25651
|
+
window.removeEventListener(COMMENT_MODE_CHANGED_EVENT, onCommentMode);
|
|
25652
|
+
};
|
|
25653
|
+
}, []);
|
|
25654
|
+
/** Bumped when the threads change, so the comments tab re-reads them (see `rememberDiscussions`). */
|
|
25655
|
+
const [commentsTick, setCommentsTick] = (0, react.useState)(0);
|
|
25656
|
+
(0, react.useEffect)(() => {
|
|
25657
|
+
const changed = () => {
|
|
25658
|
+
setCommentsTick((tick) => tick + 1);
|
|
25659
|
+
};
|
|
25660
|
+
window.addEventListener(COMMENTS_CHANGED_EVENT, changed);
|
|
25661
|
+
return () => {
|
|
25662
|
+
window.removeEventListener(COMMENTS_CHANGED_EVENT, changed);
|
|
25663
|
+
};
|
|
25664
|
+
}, []);
|
|
24440
25665
|
/** Bumped when the already-open file is clicked again, to jump to the next
|
|
24441
25666
|
* diff block in the open file's detail pane. */
|
|
24442
25667
|
const [jumpSignal, setJumpSignal] = (0, react.useState)(0);
|
|
@@ -24503,8 +25728,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24503
25728
|
* choice rides the same block RPC as its `removeWhenResolved` flag. */
|
|
24504
25729
|
const [blockPrompt, setBlockPrompt] = (0, react.useState)(null);
|
|
24505
25730
|
const [filePrompt, setFilePrompt] = (0, react.useState)(null);
|
|
25731
|
+
/** The confirm dialog's own checkbox: stop asking about this file for the rest of the page. */
|
|
25732
|
+
const [quietRemoval, setQuietRemoval] = (0, react.useState)(false);
|
|
25733
|
+
/**
|
|
25734
|
+
* Record the confirm dialog's checkbox, if it was ticked, and put it back for the next dialog.
|
|
25735
|
+
* The tick is about the questions still to come, not about the answer just given: the button the
|
|
25736
|
+
* reader presses is the answer, and it runs either way.
|
|
25737
|
+
*/
|
|
25738
|
+
const settleRemovalAsk = (id) => {
|
|
25739
|
+
if (quietRemoval) quietenRemovalAsk(current, id);
|
|
25740
|
+
setQuietRemoval(false);
|
|
25741
|
+
};
|
|
24506
25742
|
/** The file list row whose action menu is open, and where the right-click landed. */
|
|
24507
25743
|
const [rowMenu, setRowMenu] = (0, react.useState)(null);
|
|
25744
|
+
/** The comments-tab item whose menu is open, if any: which thread, and where the press landed. */
|
|
25745
|
+
const [commentMenu, setCommentMenu] = (0, react.useState)(null);
|
|
24508
25746
|
/** Whether the add-path dialog is open. One dialog covers both shapes: what
|
|
24509
25747
|
* the browser settles on decides whether a file or a directory is added. */
|
|
24510
25748
|
const [addOpen, setAddOpen] = (0, react.useState)(false);
|
|
@@ -24525,8 +25763,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24525
25763
|
/** The chord's on-screen echo: the edge just flipped, and a nonce so a repeat
|
|
24526
25764
|
* restarts the notice instead of re-rendering the same one. */
|
|
24527
25765
|
const [coverNotice, setCoverNotice] = (0, react.useState)(null);
|
|
24528
|
-
/** File-list pane width, adjustable by dragging the divider.
|
|
24529
|
-
|
|
25766
|
+
/** File-list pane width, adjustable by dragging the divider. It opens AT the floor, which is the
|
|
25767
|
+
* width the bulk footer needs for its three labels, so a fresh pane cannot wrap them either. */
|
|
25768
|
+
const [listWidth, setListWidth] = (0, react.useState)(260);
|
|
24530
25769
|
/** Whether the floating (collapsed) file list is currently shown. */
|
|
24531
25770
|
const [floatOpen, setFloatOpen] = (0, react.useState)(false);
|
|
24532
25771
|
/** Whether the file list is always folded, whatever the width allows. */
|
|
@@ -24783,6 +26022,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24783
26022
|
const blockKeepWithPrompt = (sessionId, id, block, removeWhenResolved) => {
|
|
24784
26023
|
const file = files.find((entry) => entry.id === id);
|
|
24785
26024
|
if (removeWhenResolved === void 0 && file !== void 0 && blockResolvesWholeFile(file, block)) {
|
|
26025
|
+
if (removalAskQuiet(current, id)) return onBlockKeep(sessionId, id, block, false);
|
|
24786
26026
|
setBlockPrompt({
|
|
24787
26027
|
action: "keep",
|
|
24788
26028
|
sessionId,
|
|
@@ -24796,6 +26036,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24796
26036
|
const blockRevertWithPrompt = (sessionId, id, block, removeWhenResolved) => {
|
|
24797
26037
|
const file = files.find((entry) => entry.id === id);
|
|
24798
26038
|
if (removeWhenResolved === void 0 && file !== void 0 && blockResolvesWholeFile(file, block)) {
|
|
26039
|
+
if (removalAskQuiet(current, id)) return onBlockRevert(sessionId, id, block, false);
|
|
24799
26040
|
setBlockPrompt({
|
|
24800
26041
|
action: "revert",
|
|
24801
26042
|
sessionId,
|
|
@@ -24808,6 +26049,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24808
26049
|
};
|
|
24809
26050
|
const keepWithPrompt = (sessionId, id, keepListed) => {
|
|
24810
26051
|
if (keepListed === void 0 && confirmFileRemoveEnabled()) {
|
|
26052
|
+
if (removalAskQuiet(current, id)) return onKeep(sessionId, id, true);
|
|
24811
26053
|
setFilePrompt({
|
|
24812
26054
|
action: "keep",
|
|
24813
26055
|
sessionId,
|
|
@@ -24819,6 +26061,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24819
26061
|
};
|
|
24820
26062
|
const revertWithPrompt = (sessionId, id, keepListed) => {
|
|
24821
26063
|
if (keepListed === void 0 && confirmFileRemoveEnabled()) {
|
|
26064
|
+
if (removalAskQuiet(current, id)) return onRevert(sessionId, id, true);
|
|
24822
26065
|
setFilePrompt({
|
|
24823
26066
|
action: "revert",
|
|
24824
26067
|
sessionId,
|
|
@@ -25118,6 +26361,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25118
26361
|
if (value === void 0) return false;
|
|
25119
26362
|
if (value.outcome !== "added" && value.outcome !== "duplicate") return false;
|
|
25120
26363
|
if (value.id !== void 0) setPendingSelect(value.id);
|
|
26364
|
+
onRefresh(current);
|
|
25121
26365
|
return true;
|
|
25122
26366
|
};
|
|
25123
26367
|
const renderEntry = (entry) => (0, react_jsx_runtime.jsx)(PendingFileRow, {
|
|
@@ -25166,6 +26410,60 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25166
26410
|
};
|
|
25167
26411
|
const selectedFile = files.find((file) => file.id === selected);
|
|
25168
26412
|
/**
|
|
26413
|
+
* Every comment the files in the list carry, in list order and then in the order their rows run:
|
|
26414
|
+
* what the comments tab shows. A comment IS a block of rows in one file, so its label is the same
|
|
26415
|
+
* `path:lines` reference the thread's own header wears, its title is the first sentence of what
|
|
26416
|
+
* the reader asked (the first turn is the annotation; later ones are follow-ups), and an outdated
|
|
26417
|
+
* one says so — the same state the block itself is wearing (see `[data-lost]`).
|
|
26418
|
+
*
|
|
26419
|
+
* The threads are held by the file detail, which is one mount at a time, so they are read back
|
|
26420
|
+
* out of the memory the two share, and re-read whenever they change (`commentsTick`).
|
|
26421
|
+
*/
|
|
26422
|
+
const commentEntries = (0, react.useMemo)(() => {
|
|
26423
|
+
const threads = rememberedDiscussions(current);
|
|
26424
|
+
return files.flatMap((file) => (threads[file.id] ?? []).map((discussion) => ({
|
|
26425
|
+
id: discussion.id,
|
|
26426
|
+
fileId: file.id,
|
|
26427
|
+
row: discussion.anchor.start,
|
|
26428
|
+
end: discussion.anchor.end,
|
|
26429
|
+
label: referenceLabelOf(file.path, snapshot.workspacePath, discussion.anchor.startLine, discussion.anchor.endLine),
|
|
26430
|
+
title: commentTitle(discussion) || t("panel.commentEmptyTitle"),
|
|
26431
|
+
lost: discussion.lost === true
|
|
26432
|
+
})));
|
|
26433
|
+
}, [
|
|
26434
|
+
files,
|
|
26435
|
+
current,
|
|
26436
|
+
snapshot.workspacePath,
|
|
26437
|
+
commentsTick,
|
|
26438
|
+
t
|
|
26439
|
+
]);
|
|
26440
|
+
/** Open the file a comment hangs in and land on the comment: the rows it names, or — for an outdated
|
|
26441
|
+
* thread, whose code is gone — its own box, which is the only place that says anything. */
|
|
26442
|
+
const jumpToComment = (fileId, row, card = false) => {
|
|
26443
|
+
if (fileId !== selected) setSelected(fileId);
|
|
26444
|
+
landOn(fileId, void 0, row, card);
|
|
26445
|
+
};
|
|
26446
|
+
/**
|
|
26447
|
+
* The comment menu's rows: the one action a thread has, named exactly as the block's own
|
|
26448
|
+
* overflow menu names it — ending a comment is one thing, and the pane it is asked from must
|
|
26449
|
+
* not look like it does something else.
|
|
26450
|
+
*/
|
|
26451
|
+
const commentMenuItems = (0, react.useMemo)(() => [{
|
|
26452
|
+
id: "close",
|
|
26453
|
+
label: t("action.discussionEnd")
|
|
26454
|
+
}], [t]);
|
|
26455
|
+
/**
|
|
26456
|
+
* End one comment from the list. The threads belong to the file detail, so the list does not
|
|
26457
|
+
* reach into its state: it forgets the thread in the page's memory, and the detail picks that
|
|
26458
|
+
* up (see `forgetDiscussion`), which is also what takes the block out of the open file.
|
|
26459
|
+
*/
|
|
26460
|
+
const runCommentMenu = (id) => {
|
|
26461
|
+
const target = commentMenu;
|
|
26462
|
+
setCommentMenu(null);
|
|
26463
|
+
if (target === null || id !== "close") return;
|
|
26464
|
+
forgetDiscussion(current, target.fileId, target.id);
|
|
26465
|
+
};
|
|
26466
|
+
/**
|
|
25169
26467
|
* The folded card's own box, derived from the measured one, or undefined while
|
|
25170
26468
|
* the list is not folded open. The card and its width grip are both placed from
|
|
25171
26469
|
* these numbers, which is what keeps the grip on the card's right edge as the
|
|
@@ -25181,59 +26479,126 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25181
26479
|
const promptFile = blockPrompt === null ? void 0 : files.find((file) => file.id === blockPrompt.id);
|
|
25182
26480
|
/** The file whose removal is being confirmed (a whole-file action), if any. */
|
|
25183
26481
|
const promptEntry = filePrompt === null ? void 0 : files.find((file) => file.id === filePrompt.id);
|
|
25184
|
-
const fileListBody = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
25185
|
-
|
|
25186
|
-
|
|
25187
|
-
|
|
25188
|
-
|
|
25189
|
-
|
|
25190
|
-
|
|
25191
|
-
|
|
25192
|
-
|
|
25193
|
-
|
|
25194
|
-
|
|
25195
|
-
|
|
25196
|
-
|
|
25197
|
-
|
|
25198
|
-
|
|
25199
|
-
|
|
25200
|
-
|
|
25201
|
-
|
|
25202
|
-
|
|
25203
|
-
|
|
25204
|
-
|
|
25205
|
-
|
|
25206
|
-
|
|
25207
|
-
|
|
25208
|
-
|
|
25209
|
-
|
|
25210
|
-
|
|
25211
|
-
|
|
25212
|
-
|
|
25213
|
-
|
|
25214
|
-
|
|
25215
|
-
|
|
25216
|
-
|
|
25217
|
-
|
|
25218
|
-
|
|
25219
|
-
|
|
25220
|
-
|
|
25221
|
-
|
|
26482
|
+
const fileListBody = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [files.length > 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
26483
|
+
className: PendingPanel_module_css_default.listHead,
|
|
26484
|
+
children: [
|
|
26485
|
+
listTabs.length > 1 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
26486
|
+
className: PendingPanel_module_css_default.listTabs,
|
|
26487
|
+
role: "tablist",
|
|
26488
|
+
"aria-label": t("panel.tabs"),
|
|
26489
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
26490
|
+
type: "button",
|
|
26491
|
+
role: "tab",
|
|
26492
|
+
className: PendingPanel_module_css_default.listTab,
|
|
26493
|
+
"data-diff-list-tab": "pending",
|
|
26494
|
+
"aria-selected": activeTab === "pending",
|
|
26495
|
+
onClick: () => {
|
|
26496
|
+
setListTab("pending");
|
|
26497
|
+
},
|
|
26498
|
+
children: t("panel.tab.pending")
|
|
26499
|
+
}), (0, react_jsx_runtime.jsxs)("button", {
|
|
26500
|
+
type: "button",
|
|
26501
|
+
role: "tab",
|
|
26502
|
+
className: PendingPanel_module_css_default.listTab,
|
|
26503
|
+
"data-diff-list-tab": "comments",
|
|
26504
|
+
"aria-selected": activeTab === "comments",
|
|
26505
|
+
onClick: () => {
|
|
26506
|
+
setListTab("comments");
|
|
26507
|
+
},
|
|
26508
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("panel.tab.comments") }), commentEntries.length > 0 && (0, react_jsx_runtime.jsx)("span", {
|
|
26509
|
+
className: PendingPanel_module_css_default.tabCount,
|
|
26510
|
+
"data-diff-list-count": true,
|
|
26511
|
+
children: commentEntries.length
|
|
26512
|
+
})]
|
|
26513
|
+
})]
|
|
26514
|
+
}) : (0, react_jsx_runtime.jsx)("h3", {
|
|
26515
|
+
className: PendingPanel_module_css_default.listTitle,
|
|
26516
|
+
"data-diff-list-title": true,
|
|
26517
|
+
children: t(`panel.tab.${activeTab}`)
|
|
26518
|
+
}),
|
|
26519
|
+
listTabs.length <= 1 && (0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
|
|
26520
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
26521
|
+
label: t(forceFloat ? "action.fileListFloatOff" : "action.fileListFloatOn"),
|
|
26522
|
+
side: "bottom",
|
|
26523
|
+
delayMs: 500,
|
|
26524
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
26525
|
+
type: "button",
|
|
26526
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.addButton} ${PendingPanel_module_css_default.listFold}`,
|
|
26527
|
+
"data-diff-file-list-float": true,
|
|
26528
|
+
"data-active": forceFloat ? "" : void 0,
|
|
26529
|
+
"aria-label": t(forceFloat ? "action.fileListFloatOff" : "action.fileListFloatOn"),
|
|
26530
|
+
"aria-pressed": forceFloat,
|
|
26531
|
+
onClick: toggleForceFloat,
|
|
26532
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPanelLeftOutline16, { size: 12 })
|
|
25222
26533
|
})
|
|
25223
|
-
]
|
|
25224
|
-
}),
|
|
25225
|
-
(0, react_jsx_runtime.jsx)("div", {
|
|
25226
|
-
className: PendingPanel_module_css_default.listScroll,
|
|
25227
|
-
"data-diff-list-scroll": true,
|
|
25228
|
-
ref: attachListScroll,
|
|
25229
|
-
children: files.length > 0 && (0, react_jsx_runtime.jsx)("ul", {
|
|
25230
|
-
className: PendingPanel_module_css_default.rows,
|
|
25231
|
-
children: files.map(renderEntry)
|
|
25232
26534
|
})
|
|
25233
|
-
|
|
25234
|
-
|
|
25235
|
-
|
|
25236
|
-
|
|
26535
|
+
]
|
|
26536
|
+
}), listTab === "comments" ? (0, react_jsx_runtime.jsx)("div", {
|
|
26537
|
+
className: PendingPanel_module_css_default.listScroll,
|
|
26538
|
+
"data-diff-list-scroll": true,
|
|
26539
|
+
children: commentEntries.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
26540
|
+
className: PendingPanel_module_css_default.listEmpty,
|
|
26541
|
+
"data-diff-comments-empty": true,
|
|
26542
|
+
children: t("panel.commentsEmpty")
|
|
26543
|
+
}) : (0, react_jsx_runtime.jsx)("ul", {
|
|
26544
|
+
className: PendingPanel_module_css_default.rows,
|
|
26545
|
+
"data-diff-comment-list": true,
|
|
26546
|
+
children: commentEntries.map((entry) => (0, react_jsx_runtime.jsx)("li", {
|
|
26547
|
+
className: PendingPanel_module_css_default.row,
|
|
26548
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
26549
|
+
role: "button",
|
|
26550
|
+
tabIndex: 0,
|
|
26551
|
+
className: PendingPanel_module_css_default.commentRow,
|
|
26552
|
+
"data-diff-comment-link": entry.id,
|
|
26553
|
+
"data-mobile-nav-copy": "1",
|
|
26554
|
+
onClick: () => {
|
|
26555
|
+
jumpToComment(entry.fileId, entry.lost ? entry.end : entry.row, entry.lost);
|
|
26556
|
+
},
|
|
26557
|
+
onContextMenu: (event) => {
|
|
26558
|
+
event.preventDefault();
|
|
26559
|
+
setCommentMenu({
|
|
26560
|
+
id: entry.id,
|
|
26561
|
+
fileId: entry.fileId,
|
|
26562
|
+
x: event.clientX,
|
|
26563
|
+
y: event.clientY
|
|
26564
|
+
});
|
|
26565
|
+
},
|
|
26566
|
+
onKeyDown: (event) => {
|
|
26567
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
26568
|
+
event.preventDefault();
|
|
26569
|
+
jumpToComment(entry.fileId, entry.lost ? entry.end : entry.row, entry.lost);
|
|
26570
|
+
},
|
|
26571
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
26572
|
+
className: PendingPanel_module_css_default.commentHead,
|
|
26573
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
26574
|
+
className: PendingPanel_module_css_default.commentLabel,
|
|
26575
|
+
"data-diff-comment-label": true,
|
|
26576
|
+
children: entry.label
|
|
26577
|
+
}), entry.lost && (0, react_jsx_runtime.jsx)("span", {
|
|
26578
|
+
className: PendingPanel_module_css_default.commentLost,
|
|
26579
|
+
"data-diff-comment-lost": true,
|
|
26580
|
+
children: t("panel.commentOutdated")
|
|
26581
|
+
})]
|
|
26582
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
26583
|
+
className: PendingPanel_module_css_default.commentTitle,
|
|
26584
|
+
"data-diff-comment-title": true,
|
|
26585
|
+
children: entry.title
|
|
26586
|
+
})]
|
|
26587
|
+
})
|
|
26588
|
+
}, entry.id))
|
|
26589
|
+
})
|
|
26590
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
26591
|
+
className: PendingPanel_module_css_default.listScroll,
|
|
26592
|
+
"data-diff-list-scroll": true,
|
|
26593
|
+
ref: attachListScroll,
|
|
26594
|
+
children: files.length > 0 && (0, react_jsx_runtime.jsx)("ul", {
|
|
26595
|
+
className: PendingPanel_module_css_default.rows,
|
|
26596
|
+
children: files.map(renderEntry)
|
|
26597
|
+
})
|
|
26598
|
+
}), files.length > 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
26599
|
+
className: PendingPanel_module_css_default.bulkActions,
|
|
26600
|
+
children: [
|
|
26601
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
25237
26602
|
type: "button",
|
|
25238
26603
|
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
25239
26604
|
"data-diff-keep-all": true,
|
|
@@ -25242,7 +26607,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25242
26607
|
runBulk("keep");
|
|
25243
26608
|
},
|
|
25244
26609
|
children: bulkBusy === "keep" ? t("action.busy") : t("action.keepAll")
|
|
25245
|
-
}),
|
|
26610
|
+
}),
|
|
26611
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
25246
26612
|
type: "button",
|
|
25247
26613
|
className: PendingPanel_module_css_default.action,
|
|
25248
26614
|
"data-diff-revert-all": true,
|
|
@@ -25251,9 +26617,19 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25251
26617
|
runBulk("revert");
|
|
25252
26618
|
},
|
|
25253
26619
|
children: bulkBusy === "revert" ? t("action.busy") : t("action.revertAll")
|
|
25254
|
-
})
|
|
25255
|
-
|
|
25256
|
-
|
|
26620
|
+
}),
|
|
26621
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
26622
|
+
type: "button",
|
|
26623
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.addPath}`,
|
|
26624
|
+
"data-diff-add": true,
|
|
26625
|
+
"aria-label": t("action.addPath"),
|
|
26626
|
+
onClick: () => {
|
|
26627
|
+
setAddOpen(true);
|
|
26628
|
+
},
|
|
26629
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 12 }), t("panel.addPathGo")]
|
|
26630
|
+
})
|
|
26631
|
+
]
|
|
26632
|
+
})] })] });
|
|
25257
26633
|
const handleUndo = async (sessionId) => {
|
|
25258
26634
|
const id = await onUndo(sessionId);
|
|
25259
26635
|
if (id === void 0) return;
|
|
@@ -25422,17 +26798,28 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25422
26798
|
event.preventDefault();
|
|
25423
26799
|
const startX = event.clientX;
|
|
25424
26800
|
const startWidth = listWidth;
|
|
25425
|
-
const cap = floatMode && floatBox !== null ? Math.max(
|
|
26801
|
+
const cap = floatMode && floatBox !== null ? Math.max(260, floatBox.width - 24) : MAX_LIST_WIDTH_PX;
|
|
25426
26802
|
try {
|
|
25427
26803
|
event.currentTarget.setPointerCapture(event.pointerId);
|
|
25428
26804
|
} catch {}
|
|
25429
26805
|
document.body.style.userSelect = "none";
|
|
25430
26806
|
document.body.style.cursor = "col-resize";
|
|
26807
|
+
let latest = startWidth;
|
|
26808
|
+
let pending = 0;
|
|
25431
26809
|
const onMove = (move) => {
|
|
25432
|
-
|
|
25433
|
-
|
|
26810
|
+
latest = Math.min(Math.max(startWidth + (move.clientX - startX), 260), cap);
|
|
26811
|
+
if (pending !== 0) return;
|
|
26812
|
+
pending = requestAnimationFrame(() => {
|
|
26813
|
+
pending = 0;
|
|
26814
|
+
setListWidth(latest);
|
|
26815
|
+
});
|
|
25434
26816
|
};
|
|
25435
26817
|
const finish = () => {
|
|
26818
|
+
if (pending !== 0) {
|
|
26819
|
+
cancelAnimationFrame(pending);
|
|
26820
|
+
pending = 0;
|
|
26821
|
+
setListWidth(latest);
|
|
26822
|
+
}
|
|
25436
26823
|
document.body.style.userSelect = "";
|
|
25437
26824
|
document.body.style.cursor = "";
|
|
25438
26825
|
window.removeEventListener("pointermove", onMove);
|
|
@@ -25443,6 +26830,29 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25443
26830
|
window.addEventListener("pointerup", finish);
|
|
25444
26831
|
window.addEventListener("pointercancel", finish);
|
|
25445
26832
|
};
|
|
26833
|
+
/**
|
|
26834
|
+
* End the text selection when the press lands on the panel's chrome — blank space, a label, the
|
|
26835
|
+
* toolbar, the file list — or on a row the selection already covers (see `pressOnSelectedRow`).
|
|
26836
|
+
*
|
|
26837
|
+
* The chrome is `user-select: none` (see `.panel`), and a press on such an area is one the
|
|
26838
|
+
* browser does NOT clear the selection for: the highlight stayed up, and so did the selection
|
|
26839
|
+
* frame that goes with it, over a gesture that plainly ended. The same is true inside the code
|
|
26840
|
+
* view when the press lands on the selection's own row, which is the one content press the panel
|
|
26841
|
+
* ends itself. What IS content is otherwise left to the browser — which is also what keeps a drag
|
|
26842
|
+
* started on chrome able to select the code it runs into, since dropping the ranges first costs
|
|
26843
|
+
* the drag nothing.
|
|
26844
|
+
*/
|
|
26845
|
+
const onPanelMouseDown = (event) => {
|
|
26846
|
+
const target = event.target;
|
|
26847
|
+
if (!(target instanceof Element)) return;
|
|
26848
|
+
const live = window.getSelection();
|
|
26849
|
+
if (target.closest("[data-diff-selection-actions], [data-diff-copy]") === null && pressOnSelectedRow(target, live)) {
|
|
26850
|
+
if (typeof live?.removeAllRanges === "function") live.removeAllRanges();
|
|
26851
|
+
return;
|
|
26852
|
+
}
|
|
26853
|
+
if (target.closest(KEEPS_SELECTION) !== null) return;
|
|
26854
|
+
if (typeof live?.removeAllRanges === "function") live.removeAllRanges();
|
|
26855
|
+
};
|
|
25446
26856
|
const content = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
25447
26857
|
importToast !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
25448
26858
|
text: importToast,
|
|
@@ -25478,6 +26888,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25478
26888
|
height: viewportHeight
|
|
25479
26889
|
}),
|
|
25480
26890
|
"data-diff-approval-panel": true,
|
|
26891
|
+
onMouseDown: onPanelMouseDown,
|
|
25481
26892
|
"data-diff-docked": docked ? "" : void 0,
|
|
25482
26893
|
"aria-label": t("panel.title"),
|
|
25483
26894
|
children: [
|
|
@@ -25627,6 +27038,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25627
27038
|
undoFlash,
|
|
25628
27039
|
landingTop: landing !== void 0 && landing.fileId === selectedFile.id ? landing.top : void 0,
|
|
25629
27040
|
landingTick: landing !== void 0 && landing.fileId === selectedFile.id ? landing.n : 0,
|
|
27041
|
+
landingRow: landing !== void 0 && landing.fileId === selectedFile.id ? landing.row : void 0,
|
|
27042
|
+
landingCard: landing !== void 0 && landing.fileId === selectedFile.id ? landing.card : void 0,
|
|
27043
|
+
onLanded: () => {
|
|
27044
|
+
setLanding((current) => current === void 0 ? current : void 0);
|
|
27045
|
+
},
|
|
25630
27046
|
failedMessage: failed.get(selectedFile.id),
|
|
25631
27047
|
commentSkill: snapshot.commentSkill,
|
|
25632
27048
|
onPasteReference,
|
|
@@ -25676,33 +27092,50 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25676
27092
|
className: PendingPanel_module_css_default.confirmCard,
|
|
25677
27093
|
role: "dialog",
|
|
25678
27094
|
"aria-modal": "true",
|
|
25679
|
-
children: [
|
|
25680
|
-
|
|
25681
|
-
|
|
25682
|
-
|
|
25683
|
-
|
|
25684
|
-
|
|
25685
|
-
|
|
25686
|
-
|
|
25687
|
-
"
|
|
25688
|
-
|
|
25689
|
-
|
|
25690
|
-
|
|
25691
|
-
|
|
25692
|
-
|
|
25693
|
-
|
|
25694
|
-
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
|
|
25700
|
-
|
|
25701
|
-
|
|
25702
|
-
|
|
25703
|
-
|
|
25704
|
-
|
|
25705
|
-
|
|
27095
|
+
children: [
|
|
27096
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
27097
|
+
className: PendingPanel_module_css_default.confirmText,
|
|
27098
|
+
children: t("panel.resolvedAsk", { file: basenameOf(promptFile.path) })
|
|
27099
|
+
}),
|
|
27100
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
27101
|
+
className: PendingPanel_module_css_default.pickerCheck,
|
|
27102
|
+
title: t("panel.removalQuietHint"),
|
|
27103
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
27104
|
+
type: "checkbox",
|
|
27105
|
+
"data-diff-confirm-quiet": true,
|
|
27106
|
+
checked: quietRemoval,
|
|
27107
|
+
onChange: (event) => {
|
|
27108
|
+
setQuietRemoval(event.target.checked);
|
|
27109
|
+
}
|
|
27110
|
+
}), t("panel.removalQuiet")]
|
|
27111
|
+
}),
|
|
27112
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
27113
|
+
className: PendingPanel_module_css_default.confirmActions,
|
|
27114
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
27115
|
+
type: "button",
|
|
27116
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
27117
|
+
"data-diff-confirm-remove": true,
|
|
27118
|
+
onClick: () => {
|
|
27119
|
+
setBlockPrompt(null);
|
|
27120
|
+
const { action, sessionId, id, block } = blockPrompt;
|
|
27121
|
+
settleRemovalAsk(id);
|
|
27122
|
+
action === "keep" ? onBlockKeep(sessionId, id, block, true) : onBlockRevert(sessionId, id, block, true);
|
|
27123
|
+
},
|
|
27124
|
+
children: t("row.dismiss")
|
|
27125
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
27126
|
+
type: "button",
|
|
27127
|
+
className: PendingPanel_module_css_default.action,
|
|
27128
|
+
"data-diff-confirm-keep": true,
|
|
27129
|
+
onClick: () => {
|
|
27130
|
+
setBlockPrompt(null);
|
|
27131
|
+
const { action, sessionId, id, block } = blockPrompt;
|
|
27132
|
+
settleRemovalAsk(id);
|
|
27133
|
+
action === "keep" ? onBlockKeep(sessionId, id, block, false) : onBlockRevert(sessionId, id, block, false);
|
|
27134
|
+
},
|
|
27135
|
+
children: t("panel.keepInList")
|
|
27136
|
+
})]
|
|
27137
|
+
})
|
|
27138
|
+
]
|
|
25706
27139
|
})
|
|
25707
27140
|
}),
|
|
25708
27141
|
filePrompt !== null && promptEntry !== void 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -25712,33 +27145,50 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25712
27145
|
className: PendingPanel_module_css_default.confirmCard,
|
|
25713
27146
|
role: "dialog",
|
|
25714
27147
|
"aria-modal": "true",
|
|
25715
|
-
children: [
|
|
25716
|
-
|
|
25717
|
-
|
|
25718
|
-
|
|
25719
|
-
|
|
25720
|
-
|
|
25721
|
-
|
|
25722
|
-
|
|
25723
|
-
"
|
|
25724
|
-
|
|
25725
|
-
|
|
25726
|
-
|
|
25727
|
-
|
|
25728
|
-
|
|
25729
|
-
|
|
25730
|
-
|
|
25731
|
-
|
|
25732
|
-
|
|
25733
|
-
|
|
25734
|
-
|
|
25735
|
-
|
|
25736
|
-
|
|
25737
|
-
|
|
25738
|
-
|
|
25739
|
-
|
|
25740
|
-
|
|
25741
|
-
|
|
27148
|
+
children: [
|
|
27149
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
27150
|
+
className: PendingPanel_module_css_default.confirmText,
|
|
27151
|
+
children: t(filePrompt.action === "keep" ? "panel.fileKeptAsk" : "panel.fileRevertedAsk", { file: basenameOf(promptEntry.path) })
|
|
27152
|
+
}),
|
|
27153
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
27154
|
+
className: PendingPanel_module_css_default.pickerCheck,
|
|
27155
|
+
title: t("panel.removalQuietHint"),
|
|
27156
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
27157
|
+
type: "checkbox",
|
|
27158
|
+
"data-diff-file-confirm-quiet": true,
|
|
27159
|
+
checked: quietRemoval,
|
|
27160
|
+
onChange: (event) => {
|
|
27161
|
+
setQuietRemoval(event.target.checked);
|
|
27162
|
+
}
|
|
27163
|
+
}), t("panel.removalQuiet")]
|
|
27164
|
+
}),
|
|
27165
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
27166
|
+
className: PendingPanel_module_css_default.confirmActions,
|
|
27167
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
27168
|
+
type: "button",
|
|
27169
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
27170
|
+
"data-diff-file-confirm-remove": true,
|
|
27171
|
+
onClick: () => {
|
|
27172
|
+
setFilePrompt(null);
|
|
27173
|
+
const { action, sessionId, id } = filePrompt;
|
|
27174
|
+
settleRemovalAsk(id);
|
|
27175
|
+
action === "keep" ? onKeep(sessionId, id, false) : onRevert(sessionId, id, false);
|
|
27176
|
+
},
|
|
27177
|
+
children: t("row.dismiss")
|
|
27178
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
27179
|
+
type: "button",
|
|
27180
|
+
className: PendingPanel_module_css_default.action,
|
|
27181
|
+
"data-diff-file-confirm-keep": true,
|
|
27182
|
+
onClick: () => {
|
|
27183
|
+
setFilePrompt(null);
|
|
27184
|
+
const { action, sessionId, id } = filePrompt;
|
|
27185
|
+
settleRemovalAsk(id);
|
|
27186
|
+
action === "keep" ? onKeep(sessionId, id, true) : onRevert(sessionId, id, true);
|
|
27187
|
+
},
|
|
27188
|
+
children: t("panel.keepInList")
|
|
27189
|
+
})]
|
|
27190
|
+
})
|
|
27191
|
+
]
|
|
25742
27192
|
})
|
|
25743
27193
|
}),
|
|
25744
27194
|
rowMenu !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
@@ -25753,6 +27203,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25753
27203
|
getAnchorRect: () => new DOMRect(rowMenu.x, rowMenu.y, 0, 0),
|
|
25754
27204
|
anchor: (0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.rowMenuAnchor })
|
|
25755
27205
|
}),
|
|
27206
|
+
commentMenu !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
27207
|
+
open: true,
|
|
27208
|
+
portal: true,
|
|
27209
|
+
compact: true,
|
|
27210
|
+
items: commentMenuItems,
|
|
27211
|
+
onSelect: runCommentMenu,
|
|
27212
|
+
onClose: () => {
|
|
27213
|
+
setCommentMenu(null);
|
|
27214
|
+
},
|
|
27215
|
+
getAnchorRect: () => new DOMRect(commentMenu.x, commentMenu.y, 0, 0),
|
|
27216
|
+
anchor: (0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.rowMenuAnchor })
|
|
27217
|
+
}),
|
|
25756
27218
|
addOpen && current !== void 0 && (0, react_jsx_runtime.jsx)(PathPicker, {
|
|
25757
27219
|
rootPath: snapshot.workspacePath,
|
|
25758
27220
|
onBrowse: (path) => onBrowse(current, path),
|
|
@@ -25762,6 +27224,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25762
27224
|
setAddOpen(false);
|
|
25763
27225
|
},
|
|
25764
27226
|
t
|
|
27227
|
+
}),
|
|
27228
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
27229
|
+
className: PendingPanel_module_css_default.threadFontProbe,
|
|
27230
|
+
"data-diff-thread-font": true,
|
|
27231
|
+
"aria-hidden": "true"
|
|
25765
27232
|
})
|
|
25766
27233
|
]
|
|
25767
27234
|
})] }), docked && dockHost !== void 0 ? dockHost : document.body),
|
|
@@ -27812,6 +29279,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
27812
29279
|
"panel.readFailed": "读取待处理改动失败:{message}",
|
|
27813
29280
|
"panel.group.current": "当前会话",
|
|
27814
29281
|
"panel.group.others": "其他会话",
|
|
29282
|
+
"panel.tabs": "列表页签",
|
|
29283
|
+
"panel.tab.pending": "待审列表",
|
|
29284
|
+
"panel.tab.comments": "评论",
|
|
29285
|
+
"panel.commentsEmpty": "当前打开的文件里还没有评论",
|
|
29286
|
+
"panel.commentOutdated": "已过期",
|
|
29287
|
+
"panel.commentEmptyTitle": "(未填写)",
|
|
27815
29288
|
"panel.aria": "待处理改动",
|
|
27816
29289
|
"panel.stats": "+{added} -{removed}",
|
|
27817
29290
|
"panel.blockPosition": "第 {current}/{total} 块",
|
|
@@ -27834,8 +29307,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
27834
29307
|
"panel.tabWidthDesc": "差异中制表符的缩进宽度,可选 2 / 4 / 8 个空格(默认 4),同时作用于行宽折行测量。",
|
|
27835
29308
|
"panel.splitMode": "双栏对比",
|
|
27836
29309
|
"panel.splitModeDesc": "开启后整文件差异用左「改前」|右「当前」双栏、逐行对齐的视图展示,默认关闭使用单栏(合并)视图。",
|
|
27837
|
-
"panel.navLeadRows": "
|
|
27838
|
-
"panel.navLeadRowsDesc": "
|
|
29310
|
+
"panel.navLeadRows": "跳转行距",
|
|
29311
|
+
"panel.navLeadRowsDesc": "跳转时目标上方保留的行数(默认 2):上/下跳到差异块,或从评论列表跳到某条评论。也用于从当前滚动位置定位上/下一个差异。",
|
|
27839
29312
|
"panel.diffFontSize": "代码字号",
|
|
27840
29313
|
"panel.diffFontSizeDesc": "差异代码的文字大小(按当前字号百分比缩放,默认100%,每次 ±10%)。",
|
|
27841
29314
|
"panel.diffLineHeight": "代码行高",
|
|
@@ -27855,6 +29328,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
27855
29328
|
"panel.discussionRoundsDesc": "一条评论里保留最近几轮(你问一句、Agent 答一句算一轮),更早的整轮省略。默认 2 轮,范围 1–10。",
|
|
27856
29329
|
"panel.quickSummonDesc": "用键盘快捷键打开/关闭差异面板。点击右侧按钮后按下新的按键组合即可修改。",
|
|
27857
29330
|
"panel.recordShortcut": "按下快捷键…",
|
|
29331
|
+
"panel.key.goto": "转到行",
|
|
29332
|
+
"action.goto": "转到行",
|
|
29333
|
+
"action.gotoGo": "确定",
|
|
29334
|
+
"action.gotoCancel": "取消",
|
|
29335
|
+
"panel.gotoMissing": "第 {line} 行不在当前文件中",
|
|
27858
29336
|
"settings.keybindings": "快捷键",
|
|
27859
29337
|
"settings.keybindingsDesc": "展开后可配置各项操作的按键组合。",
|
|
27860
29338
|
"settings.comment": "评论",
|
|
@@ -27899,8 +29377,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
27899
29377
|
"discussion.promptRuleSkill": "(这是一条代码批注:先加载 {skill} skill,按它的规则回答。)",
|
|
27900
29378
|
"discussion.thinking": "思考中",
|
|
27901
29379
|
"discussion.queued": "排队等待中",
|
|
27902
|
-
"discussion.
|
|
27903
|
-
"discussion.
|
|
29380
|
+
"discussion.answering": "答复中",
|
|
29381
|
+
"discussion.outdatedQuote": "评论代码已过期:",
|
|
27904
29382
|
"discussion.hidden": "更早的 {count} 条已省略",
|
|
27905
29383
|
"discussion.failed": "这次提问失败了,可以再试一次。",
|
|
27906
29384
|
"discussion.stopped": "这次回答被停掉了,可以再问一次。",
|
|
@@ -27976,6 +29454,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
27976
29454
|
"status.missing": "该改动已不存在",
|
|
27977
29455
|
"panel.resolvedAsk": "「{file}」的所有改动都已处理,是否从列表移除?",
|
|
27978
29456
|
"panel.keepInList": "保留在列表",
|
|
29457
|
+
"panel.removalQuiet": "当前会话内不再询问该文件",
|
|
29458
|
+
"panel.removalQuietHint": "本次浏览器访问内有效:刷新页面后会重新询问。",
|
|
27979
29459
|
"panel.fileKeptAsk": "「{file}」的改动已全部保留,是否从列表移出?",
|
|
27980
29460
|
"panel.fileRevertedAsk": "「{file}」的改动已全部回退,是否从列表移出?",
|
|
27981
29461
|
"panel.confirmFileRemove": "处理整文件后询问是否移出列表",
|
|
@@ -28020,6 +29500,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28020
29500
|
"panel.readFailed": "Reading pending changes failed: {message}",
|
|
28021
29501
|
"panel.group.current": "This session",
|
|
28022
29502
|
"panel.group.others": "Other sessions",
|
|
29503
|
+
"panel.tabs": "List tabs",
|
|
29504
|
+
"panel.tab.pending": "Pending",
|
|
29505
|
+
"panel.tab.comments": "Comments",
|
|
29506
|
+
"panel.commentsEmpty": "No comments in the open files yet",
|
|
29507
|
+
"panel.commentOutdated": "Outdated",
|
|
29508
|
+
"panel.commentEmptyTitle": "(not written yet)",
|
|
28023
29509
|
"panel.aria": "Pending changes",
|
|
28024
29510
|
"panel.stats": "+{added} -{removed}",
|
|
28025
29511
|
"panel.blockPosition": "{current}/{total}",
|
|
@@ -28042,8 +29528,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28042
29528
|
"panel.tabWidthDesc": "The indent width of a tab character in the differences, as 2 / 4 / 8 spaces (default 4). Also drives the wrapped-line measurement.",
|
|
28043
29529
|
"panel.splitMode": "Side-by-side view",
|
|
28044
29530
|
"panel.splitModeDesc": "When on, the whole-file differences render as a side-by-side (left \"before\" | right \"current\") line-aligned view. Off (default) uses the single-column unified view.",
|
|
28045
|
-
"panel.navLeadRows": "
|
|
28046
|
-
"panel.navLeadRowsDesc": "Rows left above the
|
|
29531
|
+
"panel.navLeadRows": "Jump lead rows",
|
|
29532
|
+
"panel.navLeadRowsDesc": "Rows left above the target when jumping — up/down to a diff block, or from the comments list to a comment (default 2). Also used to locate the previous/next diff from the current scroll position.",
|
|
28047
29533
|
"panel.diffFontSize": "Code font size",
|
|
28048
29534
|
"panel.diffFontSizeDesc": "The diff code text size as a percentage of the current size (default 100%, ±10% per step).",
|
|
28049
29535
|
"panel.diffLineHeight": "Code line height",
|
|
@@ -28063,6 +29549,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28063
29549
|
"panel.discussionRoundsDesc": "How many rounds a comment keeps (one question and the answer to it); older rounds are left out. Default 2, range 1-10.",
|
|
28064
29550
|
"panel.quickSummonDesc": "Open or close the diff panel with a keyboard shortcut. Click the button and press a new chord to change it.",
|
|
28065
29551
|
"panel.recordShortcut": "Press keys…",
|
|
29552
|
+
"panel.key.goto": "Go to line",
|
|
29553
|
+
"action.goto": "Go to line",
|
|
29554
|
+
"action.gotoGo": "Go",
|
|
29555
|
+
"action.gotoCancel": "Cancel",
|
|
29556
|
+
"panel.gotoMissing": "Line {line} is not in the current file",
|
|
28066
29557
|
"settings.keybindings": "Shortcuts",
|
|
28067
29558
|
"settings.keybindingsDesc": "Expand to configure the key combo for each action.",
|
|
28068
29559
|
"settings.comment": "Comments",
|
|
@@ -28107,8 +29598,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28107
29598
|
"discussion.promptRuleSkill": "(This is a comment on a few diff lines: load the {skill} skill first and answer by its rules.)",
|
|
28108
29599
|
"discussion.thinking": "Thinking",
|
|
28109
29600
|
"discussion.queued": "Queued",
|
|
28110
|
-
"discussion.
|
|
28111
|
-
"discussion.
|
|
29601
|
+
"discussion.answering": "Replying",
|
|
29602
|
+
"discussion.outdatedQuote": "Commented code is outdated:",
|
|
28112
29603
|
"discussion.hidden": "{count} earlier turns omitted",
|
|
28113
29604
|
"discussion.failed": "That question failed; you can try again.",
|
|
28114
29605
|
"discussion.stopped": "That answer was stopped; you can ask again.",
|
|
@@ -28184,6 +29675,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28184
29675
|
"status.missing": "This change no longer exists",
|
|
28185
29676
|
"panel.resolvedAsk": "All changes in \"{file}\" are resolved. Remove it from the list?",
|
|
28186
29677
|
"panel.keepInList": "Keep in list",
|
|
29678
|
+
"panel.removalQuiet": "Stop asking about this file in this session",
|
|
29679
|
+
"panel.removalQuietHint": "For this browser visit only — a reload asks again.",
|
|
28187
29680
|
"panel.fileKeptAsk": "All changes in \"{file}\" are kept. Remove it from the list?",
|
|
28188
29681
|
"panel.fileRevertedAsk": "All changes in \"{file}\" are reverted. Remove it from the list?",
|
|
28189
29682
|
"panel.confirmFileRemove": "Ask after a whole-file keep/revert",
|