prreviewbuddy 0.50.0 → 0.50.1
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/CHANGELOG.md +15 -0
- package/dist/server.js +38 -22
- package/package.json +1 -1
- package/static/shell.css +6 -3
- package/static/sidebar.css +250 -34
- package/static/workspace.js +46 -46
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.50.1
|
|
4
|
+
|
|
5
|
+
**Copy and Ask Buddy look and behave as a pair.** On every issue and question, both icons are the
|
|
6
|
+
same grey at rest and share one soft highlight when you point at them. Copy no longer turns purple on
|
|
7
|
+
hover. Ask Buddy turns purple only while its menu is open. After you copy, the icon turns into a green
|
|
8
|
+
check for a moment and "Copied" appears just below it. It used to appear beside it, on top of Ask
|
|
9
|
+
Buddy. "Copy failed" shows in the same place.
|
|
10
|
+
|
|
11
|
+
The questions you can ask Buddy AI about a finding or a selection, and the wording that tells Buddy
|
|
12
|
+
which theme a question was asked in, now live in the shared review engine, so the browser extension
|
|
13
|
+
offers the same ones.
|
|
14
|
+
|
|
15
|
+
In a short window, the list of questions you can ask about a selection now scrolls instead of being
|
|
16
|
+
cut off at the bottom. Escape closes a menu again after the page has redrawn around it.
|
|
17
|
+
|
|
3
18
|
## 0.50.0
|
|
4
19
|
|
|
5
20
|
**Every review says which commits it covers.** Beside the branch at the top of a review is its
|
package/dist/server.js
CHANGED
|
@@ -208,6 +208,30 @@ function resolveSectionId(run, sectionId) {
|
|
|
208
208
|
return run.result.sections.some((section) => section.id === sectionId) ? namespaced(run.id, sectionId) : sectionId;
|
|
209
209
|
}
|
|
210
210
|
//#endregion
|
|
211
|
+
//#region ../../packages/review-harness/src/domain/ai_review/ask_scope.ts
|
|
212
|
+
/**
|
|
213
|
+
* Where an earlier question was asked, which the question alone does not say.
|
|
214
|
+
*
|
|
215
|
+
* "What is risky here?" in one theme followed by "and how does that compare?" in another reads, as
|
|
216
|
+
* bare text, as two questions about the same thing. `undefined` is a question recorded before
|
|
217
|
+
* scopes were, and gets no label: calling it "the whole change" would state something nobody
|
|
218
|
+
* recorded. A theme that has since gone, because the review was updated, is said to have gone.
|
|
219
|
+
*/
|
|
220
|
+
function askedWhere(sections, sectionId) {
|
|
221
|
+
if (sectionId === void 0) return null;
|
|
222
|
+
if (sectionId === null) return "(asked about the whole change)";
|
|
223
|
+
const section = sections.find((s) => s.id === sectionId);
|
|
224
|
+
return section ? `(asked while reading the "${section.title}" theme)` : "(asked while reading a theme that is no longer in the review)";
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* The theme the reviewer has open, named rather than used to filter what the model sees: they
|
|
228
|
+
* routinely ask "does this interact with X", where X is in another theme.
|
|
229
|
+
*/
|
|
230
|
+
function readingThemeLine(sections, sectionId) {
|
|
231
|
+
const section = sectionId === null ? void 0 : sections.find((s) => s.id === sectionId);
|
|
232
|
+
return section ? `The reviewer is currently reading the "${section.title}" theme. Answer with that in view, but do not ignore the rest of the change if it bears on the question.` : null;
|
|
233
|
+
}
|
|
234
|
+
//#endregion
|
|
211
235
|
//#region ../../packages/review-harness/src/domain/utils/html.ts
|
|
212
236
|
function escapeHtml$1(value) {
|
|
213
237
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -773,9 +797,10 @@ var FINDING_COPY_CLASS = "pr-helper-finding-copy";
|
|
|
773
797
|
* buttons, where an icon alone read as decoration. In the heading it is on its own, and a word
|
|
774
798
|
* would give a utility the weight of the title beside it. What it does is said by a hover
|
|
775
799
|
* tooltip (`data-tip`, the same CSS tooltip the pills use, not a native `title`) and by its
|
|
776
|
-
* accessible name.
|
|
777
|
-
*
|
|
778
|
-
*
|
|
800
|
+
* accessible name. After a click it shows a green check and says "Copied" (or "Copy failed") in
|
|
801
|
+
* the bubble below it, the words used everywhere else, but not inline: beside it is Ask Buddy. The
|
|
802
|
+
* resting name and tip are kept on the button so the reset returns to "Copy finding" rather than to
|
|
803
|
+
* a chat reply's "Copy message".
|
|
779
804
|
*/
|
|
780
805
|
function renderFindingCopySource(source, kind) {
|
|
781
806
|
const name = kind === "issue" ? "Copy finding" : "Copy question";
|
|
@@ -788,11 +813,12 @@ function renderFindingCopySource(source, kind) {
|
|
|
788
813
|
/** Where a finding's button keeps its resting word and name. Absent on a chat reply's. */
|
|
789
814
|
var IDLE_LABEL_ATTR = "data-copy-idle-label";
|
|
790
815
|
var IDLE_ARIA_ATTR = "data-copy-idle-aria";
|
|
816
|
+
var IDLE_TIP_ATTR = "data-copy-idle-tip";
|
|
791
817
|
function button(handle, idle) {
|
|
792
818
|
const { icon } = STATES$1.idle;
|
|
793
819
|
const label = idle?.label ?? STATES$1.idle.label;
|
|
794
820
|
const aria = idle?.aria ?? STATES$1.idle.aria;
|
|
795
|
-
const remembered = idle ? ` ${IDLE_LABEL_ATTR}="${escapeHtml$1(label)}" ${IDLE_ARIA_ATTR}="${escapeHtml$1(aria)}"` : "";
|
|
821
|
+
const remembered = idle ? ` ${IDLE_LABEL_ATTR}="${escapeHtml$1(label)}" ${IDLE_ARIA_ATTR}="${escapeHtml$1(aria)}" ${IDLE_TIP_ATTR}="${escapeHtml$1(idle.tip)}"` : "";
|
|
796
822
|
const control = `<button type="button" class="${idle ? `${MESSAGE_COPY_CLASS} ${FINDING_COPY_CLASS}` : MESSAGE_COPY_CLASS}" ${handle}${remembered}${idle ? ` data-tip="${escapeHtml$1(idle.tip)}"` : ""} aria-label="${escapeHtml$1(aria)}"><span class="${MESSAGE_COPY_CLASS}-icon" aria-hidden="true">${svg(icon)}</span><span class="${MESSAGE_COPY_CLASS}-label"${label ? "" : " hidden"}>${escapeHtml$1(label)}</span></button>`;
|
|
797
823
|
return idle ? control : `<div class="${MESSAGE_ACTIONS_CLASS}">${control}</div>`;
|
|
798
824
|
}
|
|
@@ -813,8 +839,7 @@ function svg(paths) {
|
|
|
813
839
|
* closes and positions exactly as that one does. The panel is empty here and filled when it opens,
|
|
814
840
|
* because it lists the reviewer's saved prompts and those change without the page re-rendering.
|
|
815
841
|
*
|
|
816
|
-
*
|
|
817
|
-
* there for this to open, so `ReviewTabOptions.askBuddy` gates it and the extension never sets it.
|
|
842
|
+
* The host decides where the answer appears; `ReviewTabOptions.askBuddy` says the host has wired it.
|
|
818
843
|
*/
|
|
819
844
|
var ASK_BUDDY_LABEL = "Ask Buddy";
|
|
820
845
|
/** Four-point sparkle, the conventional mark for "ask the AI". currentColor, like Copy beside it. */
|
|
@@ -8362,7 +8387,8 @@ function extractAnswer(raw) {
|
|
|
8362
8387
|
* and wrongly.
|
|
8363
8388
|
*/
|
|
8364
8389
|
function buildPrompt$2(workspace, question, sectionId, cwd) {
|
|
8365
|
-
const
|
|
8390
|
+
const sections = workspace.session.result?.sections ?? [];
|
|
8391
|
+
const reading = readingThemeLine(sections, sectionId);
|
|
8366
8392
|
const recent = workspace.transcript.slice(-4);
|
|
8367
8393
|
return [
|
|
8368
8394
|
SYSTEM_PROMPT$1,
|
|
@@ -8374,29 +8400,19 @@ function buildPrompt$2(workspace, question, sectionId, cwd) {
|
|
|
8374
8400
|
"---",
|
|
8375
8401
|
"DIFF:",
|
|
8376
8402
|
workspace.diff,
|
|
8377
|
-
...
|
|
8403
|
+
...reading ? ["---", reading] : [],
|
|
8378
8404
|
...recent.length > 0 ? [
|
|
8379
8405
|
"---",
|
|
8380
8406
|
"EARLIER IN THIS CONVERSATION:",
|
|
8381
|
-
recent.map((entry) =>
|
|
8407
|
+
recent.map((entry) => {
|
|
8408
|
+
const where = askedWhere(sections, entry.sectionId);
|
|
8409
|
+
return `Q${where ? ` ${where}` : ""}: ${entry.question}\nA: ${entry.answer}`;
|
|
8410
|
+
}).join("\n\n")
|
|
8382
8411
|
] : [],
|
|
8383
8412
|
"---",
|
|
8384
8413
|
`QUESTION: ${question}`
|
|
8385
8414
|
].join("\n");
|
|
8386
8415
|
}
|
|
8387
|
-
/**
|
|
8388
|
-
* Where an earlier question was asked, which the question alone does not say.
|
|
8389
|
-
*
|
|
8390
|
-
* "What is risky here?" in one theme followed by "and how does that compare?" in another reads, as
|
|
8391
|
-
* bare text, as two questions about the same thing. A theme that has since gone, because the
|
|
8392
|
-
* review was updated, is said to have gone rather than dropped: dropping it would present a
|
|
8393
|
-
* theme's question as one about the whole change.
|
|
8394
|
-
*/
|
|
8395
|
-
function askedWhere(workspace, sectionId) {
|
|
8396
|
-
if (sectionId === null) return "(asked about the whole change)";
|
|
8397
|
-
const section = workspace.session.result?.sections.find((s) => s.id === sectionId);
|
|
8398
|
-
return section ? `(asked while reading the "${section.title}" theme)` : "(asked while reading a theme that is no longer in the review)";
|
|
8399
|
-
}
|
|
8400
8416
|
//#endregion
|
|
8401
8417
|
//#region ../../packages/review-harness/src/workspace/assistant_runs.ts
|
|
8402
8418
|
var RUN_KINDS = ["ask", "diagram"];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prreviewbuddy",
|
|
3
|
-
"version": "0.50.
|
|
3
|
+
"version": "0.50.1",
|
|
4
4
|
"description": "Review a branch or pull request in an isolated checkout, from your terminal, with the coding agent you already have installed.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"homepage": "https://prreviewbuddy.com",
|
package/static/shell.css
CHANGED
|
@@ -5165,10 +5165,13 @@ body .prb-body[data-focus='buddy'] .prb-msg-user { max-width: min(90%, 78ch); }
|
|
|
5165
5165
|
width: 24px;
|
|
5166
5166
|
height: 24px;
|
|
5167
5167
|
margin-top: -3px;
|
|
5168
|
-
|
|
5168
|
+
border-radius: 6px;
|
|
5169
|
+
color: var(--pane-ink-muted);
|
|
5169
5170
|
}
|
|
5170
|
-
|
|
5171
|
-
|
|
5171
|
+
/* Copy beside it has the same rest, hover and size (sidebar.css): grey, a soft surface, and purple
|
|
5172
|
+
only while this menu is open, because then it is the AI action in play. */
|
|
5173
|
+
.prb-doc .prb-ask-buddy-trigger:hover { background: rgba(31, 35, 40, 0.07); color: var(--pane-ink-muted); }
|
|
5174
|
+
.prb-doc .prb-ask-buddy-trigger[aria-expanded='true'] { background: rgba(130, 80, 223, 0.1); color: var(--pane-accent-ink); }
|
|
5172
5175
|
.prb-doc .prb-ask-buddy-trigger:focus-visible { outline: 2px solid var(--pane-accent); outline-offset: -2px; }
|
|
5173
5176
|
|
|
5174
5177
|
/* The tooltip Copy uses beside it, so the two icons explain themselves the same way. */
|
package/static/sidebar.css
CHANGED
|
@@ -653,6 +653,51 @@
|
|
|
653
653
|
margin-top: 2px;
|
|
654
654
|
}
|
|
655
655
|
|
|
656
|
+
/* The extension's cards, laid out as the workspace's are: the figure leads and the label sits
|
|
657
|
+
beside it, pinned to the top row so four cards align with or without a note. Only once each
|
|
658
|
+
card has the room: at the sidebar's narrowest a quarter-width card cannot hold "Questions" beside
|
|
659
|
+
its figure, and the stacked card above stays. The grid is the query container because the rule
|
|
660
|
+
only needs its children; nothing else in the panel is contained. Selectors carry the extension
|
|
661
|
+
class, so they outrank the base rules wherever those sit in the file. */
|
|
662
|
+
.pr-helper-extension .pr-helper-overview-stats { container-type: inline-size; }
|
|
663
|
+
|
|
664
|
+
@container (min-width: 400px) {
|
|
665
|
+
.pr-helper-extension .pr-helper-overview-stat {
|
|
666
|
+
display: grid;
|
|
667
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
668
|
+
grid-template-rows: auto 1fr;
|
|
669
|
+
column-gap: 8px;
|
|
670
|
+
align-items: start;
|
|
671
|
+
padding: 10px 12px;
|
|
672
|
+
text-align: left;
|
|
673
|
+
}
|
|
674
|
+
.pr-helper-extension .pr-helper-overview-stat-value {
|
|
675
|
+
grid-column: 1;
|
|
676
|
+
grid-row: 1 / span 2;
|
|
677
|
+
font-size: 24px;
|
|
678
|
+
font-weight: 300;
|
|
679
|
+
line-height: 1;
|
|
680
|
+
font-variant-numeric: tabular-nums;
|
|
681
|
+
}
|
|
682
|
+
.pr-helper-extension .pr-helper-overview-stat-value-wide { font-size: 15px; }
|
|
683
|
+
.pr-helper-extension .pr-helper-overview-stat-label {
|
|
684
|
+
grid-column: 2;
|
|
685
|
+
grid-row: 1;
|
|
686
|
+
justify-self: start;
|
|
687
|
+
/* Squares the label's cap height with the figure's top. */
|
|
688
|
+
margin-top: 5px;
|
|
689
|
+
}
|
|
690
|
+
.pr-helper-extension .pr-helper-overview-stat-note {
|
|
691
|
+
grid-column: 2;
|
|
692
|
+
grid-row: 2;
|
|
693
|
+
justify-self: start;
|
|
694
|
+
}
|
|
695
|
+
/* Into flow, ahead of the word, now that nothing is centred for it to compensate. */
|
|
696
|
+
.pr-helper-extension .pr-helper-overview-stat-info { position: static; transform: none; }
|
|
697
|
+
/* The whole card lights up as the link, so the arrow only pushed the label off the figure. */
|
|
698
|
+
.pr-helper-extension .pr-helper-overview-stat-arrow { display: none; }
|
|
699
|
+
}
|
|
700
|
+
|
|
656
701
|
/* Explains a capped review, and only ever appears on one. Sits ahead of the 11px label rather
|
|
657
702
|
than beside the value, so it's sized to that row — against the bold number it read as a
|
|
658
703
|
glyph belonging to the count. */
|
|
@@ -895,11 +940,30 @@
|
|
|
895
940
|
.pr-helper-finding-copy {
|
|
896
941
|
position: relative;
|
|
897
942
|
flex-shrink: 0;
|
|
898
|
-
margin-top: -1px;
|
|
899
943
|
opacity: 1;
|
|
900
944
|
font-size: 12px;
|
|
901
945
|
}
|
|
902
946
|
|
|
947
|
+
/* Copy and Ask Buddy are a pair and speak one interaction language, on both surfaces: the same
|
|
948
|
+
24px target and 6px corner, neutral grey at rest, and a soft surface on hover with the icon
|
|
949
|
+
colour left alone. Colour is kept for meaning: purple for an Ask Buddy menu that is open, and
|
|
950
|
+
the app's green or red for what Copy just did (.pr-helper-msg-copy.copied / .failed below). Pulled up 3px so the box centres on the title's first line.
|
|
951
|
+
Doubled class: the chat's .pr-helper-msg-copy rules sit later in this file and would win a tie. */
|
|
952
|
+
.pr-helper-msg-copy.pr-helper-finding-copy {
|
|
953
|
+
justify-content: center;
|
|
954
|
+
width: 24px;
|
|
955
|
+
height: 24px;
|
|
956
|
+
margin-top: -3px;
|
|
957
|
+
padding: 0;
|
|
958
|
+
border-radius: 6px;
|
|
959
|
+
color: var(--color-fg-muted, #57606a);
|
|
960
|
+
}
|
|
961
|
+
.pr-helper-finding-copy:hover:not(.copied):not(.failed) {
|
|
962
|
+
background: rgba(31, 35, 40, 0.07);
|
|
963
|
+
color: var(--color-fg-muted, #57606a);
|
|
964
|
+
}
|
|
965
|
+
.pr-helper-finding-copy:focus-visible { outline: 2px solid #9333ea; outline-offset: -2px; }
|
|
966
|
+
|
|
903
967
|
/* The tooltip grows leftward from the right edge, back over the card rather than out of the pane,
|
|
904
968
|
and stays on one line. The same look, delay and text reset as `.pr-helper-tip`, which it cannot
|
|
905
969
|
reuse: that one pins itself to its positioned row, and this control is its own anchor. */
|
|
@@ -929,10 +993,82 @@
|
|
|
929
993
|
transition-delay: 0.35s;
|
|
930
994
|
}
|
|
931
995
|
|
|
932
|
-
/*
|
|
933
|
-
|
|
996
|
+
/* After a click the bubble carries "Copied" or "Copy failed" and shows without waiting for the
|
|
997
|
+
pointer: below the button rather than beside it, where Ask Buddy sits. */
|
|
934
998
|
.pr-helper-finding-copy.copied::after,
|
|
935
|
-
.pr-helper-finding-copy.failed::after {
|
|
999
|
+
.pr-helper-finding-copy.failed::after { opacity: 1; transition-delay: 0s; }
|
|
1000
|
+
|
|
1001
|
+
/* Ask Buddy on a finding card, in the extension: the sparkle beside Copy, and its menu. Scoped to
|
|
1002
|
+
.pr-helper-extension, which only the extension's root carries: the workspace loads this sheet
|
|
1003
|
+
too, its review document is also a .pr-helper-sidebar, and it styles its own menu in shell.css
|
|
1004
|
+
under .prb-doc. The panel matches the selection popover, which offers the same list. */
|
|
1005
|
+
.pr-helper-extension .prb-ask-buddy { position: relative; flex-shrink: 0; }
|
|
1006
|
+
.pr-helper-extension .prb-ask-buddy-trigger {
|
|
1007
|
+
position: relative;
|
|
1008
|
+
display: inline-flex;
|
|
1009
|
+
align-items: center;
|
|
1010
|
+
justify-content: center;
|
|
1011
|
+
width: 24px;
|
|
1012
|
+
height: 24px;
|
|
1013
|
+
margin-top: -3px;
|
|
1014
|
+
padding: 0;
|
|
1015
|
+
border: 0;
|
|
1016
|
+
border-radius: 6px;
|
|
1017
|
+
background: transparent;
|
|
1018
|
+
color: var(--color-fg-muted, #57606a);
|
|
1019
|
+
cursor: pointer;
|
|
1020
|
+
}
|
|
1021
|
+
.pr-helper-extension .prb-ask-buddy-trigger:hover { background: rgba(31, 35, 40, 0.07); }
|
|
1022
|
+
.pr-helper-extension .prb-ask-buddy-trigger[aria-expanded='true'] { background: rgba(147, 51, 234, 0.1); color: #9333ea; }
|
|
1023
|
+
.pr-helper-extension .prb-ask-buddy-trigger:focus-visible { outline: 2px solid #9333ea; outline-offset: -2px; }
|
|
1024
|
+
.pr-helper-extension .prb-ask-buddy-trigger::after {
|
|
1025
|
+
content: attr(data-tip);
|
|
1026
|
+
position: absolute;
|
|
1027
|
+
top: calc(100% + 6px);
|
|
1028
|
+
right: 0;
|
|
1029
|
+
z-index: 3;
|
|
1030
|
+
padding: 5px 8px;
|
|
1031
|
+
border-radius: 6px;
|
|
1032
|
+
background: #24292f;
|
|
1033
|
+
color: #ffffff;
|
|
1034
|
+
font-size: 11px;
|
|
1035
|
+
font-weight: 400;
|
|
1036
|
+
font-family: inherit;
|
|
1037
|
+
line-height: 1.4;
|
|
1038
|
+
white-space: nowrap;
|
|
1039
|
+
opacity: 0;
|
|
1040
|
+
pointer-events: none;
|
|
1041
|
+
transition: opacity 0.1s;
|
|
1042
|
+
}
|
|
1043
|
+
.pr-helper-extension .prb-ask-buddy-trigger:hover::after,
|
|
1044
|
+
.pr-helper-extension .prb-ask-buddy-trigger:focus-visible::after { opacity: 1; transition-delay: 0.35s; }
|
|
1045
|
+
.pr-helper-extension .prb-ask-buddy-trigger[aria-expanded='true']::after { display: none; }
|
|
1046
|
+
.pr-helper-extension .prb-ask-buddy-panel {
|
|
1047
|
+
position: absolute;
|
|
1048
|
+
top: 26px;
|
|
1049
|
+
right: 0;
|
|
1050
|
+
z-index: 5;
|
|
1051
|
+
width: 240px;
|
|
1052
|
+
max-width: calc(100vw - 48px);
|
|
1053
|
+
padding: 4px;
|
|
1054
|
+
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
1055
|
+
border-radius: 8px;
|
|
1056
|
+
background: #ffffff;
|
|
1057
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
|
|
1058
|
+
text-align: left;
|
|
1059
|
+
}
|
|
1060
|
+
/* The card whose menu is open comes forward. A dismissed card's opacity makes it its own layer,
|
|
1061
|
+
where the panel's z-index counts only inside the card: the next card's Copy and sparkle painted
|
|
1062
|
+
across the open menu, and the menu was drawn faded. */
|
|
1063
|
+
.pr-helper-extension [data-finding-card]:has(.prb-ask-buddy-trigger[aria-expanded='true']) {
|
|
1064
|
+
position: relative;
|
|
1065
|
+
z-index: 6;
|
|
1066
|
+
opacity: 1;
|
|
1067
|
+
}
|
|
1068
|
+
.pr-helper-extension .prb-ask-buddy-panel .pr-helper-selection-menu-item { display: block; width: 100%; text-align: left; }
|
|
1069
|
+
.pr-helper-extension .prb-ask-buddy-panel .pr-helper-selection-menu-item[disabled] { opacity: 0.5; cursor: default; }
|
|
1070
|
+
/* Arrow keys move focus through these items, so the focus has to show. */
|
|
1071
|
+
.pr-helper-extension .prb-ask-buddy-panel .pr-helper-selection-menu-item:focus-visible { outline: 2px solid #9333ea; outline-offset: -2px; }
|
|
936
1072
|
|
|
937
1073
|
.pr-helper-issue-desc {
|
|
938
1074
|
font-size: 13px;
|
|
@@ -2050,6 +2186,15 @@
|
|
|
2050
2186
|
|
|
2051
2187
|
.pr-helper-markdown a:hover { text-decoration: underline; }
|
|
2052
2188
|
|
|
2189
|
+
/* State, not decoration: it changes what the next question means. Wraps rather than truncates. */
|
|
2190
|
+
.pr-helper-ask-scope {
|
|
2191
|
+
margin: 0 0 6px;
|
|
2192
|
+
font-size: 12px;
|
|
2193
|
+
color: var(--color-fg-muted, #57606a);
|
|
2194
|
+
overflow-wrap: anywhere;
|
|
2195
|
+
}
|
|
2196
|
+
.pr-helper-ask-scope-value { color: var(--color-fg-default, #24292f); }
|
|
2197
|
+
|
|
2053
2198
|
.pr-helper-chat-input-row {
|
|
2054
2199
|
display: flex;
|
|
2055
2200
|
gap: 6px;
|
|
@@ -2133,7 +2278,8 @@
|
|
|
2133
2278
|
|
|
2134
2279
|
/* Deliberately quieter than the chips it reveals: once the reviewer is typing their own
|
|
2135
2280
|
questions, this is a door they may never open again, not a call to action. */
|
|
2136
|
-
.pr-helper-suggestions-toggle
|
|
2281
|
+
.pr-helper-suggestions-toggle,
|
|
2282
|
+
.pr-helper-saved-prompts-toggle {
|
|
2137
2283
|
display: flex;
|
|
2138
2284
|
align-items: center;
|
|
2139
2285
|
gap: 5px;
|
|
@@ -2149,9 +2295,11 @@
|
|
|
2149
2295
|
cursor: pointer;
|
|
2150
2296
|
}
|
|
2151
2297
|
|
|
2152
|
-
.pr-helper-suggestions-toggle:hover
|
|
2298
|
+
.pr-helper-suggestions-toggle:hover,
|
|
2299
|
+
.pr-helper-saved-prompts-toggle:hover { color: #9333ea; }
|
|
2153
2300
|
|
|
2154
|
-
.pr-helper-suggestions-toggle::before
|
|
2301
|
+
.pr-helper-suggestions-toggle::before,
|
|
2302
|
+
.pr-helper-saved-prompts-toggle::before {
|
|
2155
2303
|
content: '';
|
|
2156
2304
|
width: 0;
|
|
2157
2305
|
height: 0;
|
|
@@ -2161,10 +2309,12 @@
|
|
|
2161
2309
|
transition: transform 0.15s ease;
|
|
2162
2310
|
}
|
|
2163
2311
|
|
|
2164
|
-
.pr-helper-suggestions-toggle[aria-expanded='true']::before
|
|
2312
|
+
.pr-helper-suggestions-toggle[aria-expanded='true']::before,
|
|
2313
|
+
.pr-helper-saved-prompts-toggle[aria-expanded='true']::before { transform: rotate(90deg); }
|
|
2165
2314
|
|
|
2166
2315
|
/* Open, the toggle is a label for the list right beneath it rather than a lone control. */
|
|
2167
|
-
.pr-helper-suggestions-toggle[aria-expanded='true']
|
|
2316
|
+
.pr-helper-suggestions-toggle[aria-expanded='true'],
|
|
2317
|
+
.pr-helper-saved-prompts-toggle[aria-expanded='true'] { margin-bottom: 8px; }
|
|
2168
2318
|
|
|
2169
2319
|
.pr-helper-quick-prompts {
|
|
2170
2320
|
display: flex;
|
|
@@ -2187,7 +2337,13 @@
|
|
|
2187
2337
|
.pr-helper-quick-prompt-button:hover { border-color: #9333ea; color: #9333ea; }
|
|
2188
2338
|
|
|
2189
2339
|
.pr-helper-quick-prompts-section-group,
|
|
2190
|
-
|
|
2340
|
+
/* Its own block below the suggestions, not part of their stack: that stack folds away after the
|
|
2341
|
+
first question, and Your prompts stays as the reviewer left it. */
|
|
2342
|
+
.pr-helper-quick-prompts-saved-group { margin-bottom: 8px; }
|
|
2343
|
+
/* .pr-helper-quick-prompts is a flex row, which beats the hidden attribute. */
|
|
2344
|
+
#pr-helper-saved-prompts-list[hidden] { display: none; }
|
|
2345
|
+
/* The count is a quantity, not part of the heading, so it drops the heading's caps and weight. */
|
|
2346
|
+
.pr-helper-saved-prompts-count { font-weight: 600; text-transform: none; letter-spacing: 0; }
|
|
2191
2347
|
|
|
2192
2348
|
/* ── The reviewer's own prompts ──
|
|
2193
2349
|
The chip and its edit control read as one object, so the border and the hover colour belong to
|
|
@@ -2887,7 +3043,9 @@
|
|
|
2887
3043
|
transition: opacity 0.12s;
|
|
2888
3044
|
}
|
|
2889
3045
|
|
|
2890
|
-
.pr-helper-file-item:hover .pr-helper-file-stats
|
|
3046
|
+
.pr-helper-file-item:hover .pr-helper-file-stats,
|
|
3047
|
+
.pr-helper-file-item:focus-within .pr-helper-file-stats,
|
|
3048
|
+
.pr-helper-file-item:has(.pr-helper-file-actions [aria-expanded='true']) .pr-helper-file-stats { opacity: 0; }
|
|
2891
3049
|
|
|
2892
3050
|
/* ── Hover-reveal action buttons ── */
|
|
2893
3051
|
.pr-helper-file-actions {
|
|
@@ -2902,38 +3060,85 @@
|
|
|
2902
3060
|
transition: opacity 0.12s;
|
|
2903
3061
|
}
|
|
2904
3062
|
|
|
2905
|
-
/*
|
|
2906
|
-
|
|
3063
|
+
/* One trigger, the row's "more actions", in the icon language Copy and Ask Buddy use: neutral grey,
|
|
3064
|
+
a soft surface on hover, colour only when it means something. It sits where the +/- stats are,
|
|
3065
|
+
which already give way on hover. Revealed by keyboard focus as well as the pointer, and held
|
|
3066
|
+
while its menu is open, so the menu does not vanish when the pointer leaves the row. */
|
|
3067
|
+
.pr-helper-file-item:hover .pr-helper-file-actions,
|
|
3068
|
+
.pr-helper-file-item:focus-within .pr-helper-file-actions,
|
|
3069
|
+
.pr-helper-file-actions:has([aria-expanded='true']) {
|
|
3070
|
+
opacity: 1;
|
|
3071
|
+
pointer-events: auto;
|
|
3072
|
+
}
|
|
2907
3073
|
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
3074
|
+
/* Top right, level with the +/- stats it replaces on hover, rather than centred down a tall row.
|
|
3075
|
+
No transform: one would make the tray its own stacking context, and the next row would paint
|
|
3076
|
+
over the open menu. Raised while open for the same reason. */
|
|
3077
|
+
.pr-helper-file-actions[data-menu] {
|
|
3078
|
+
top: 13px;
|
|
3079
|
+
right: 12px;
|
|
3080
|
+
transform: none;
|
|
3081
|
+
}
|
|
3082
|
+
.pr-helper-file-actions:has([aria-expanded='true']) { z-index: 10; }
|
|
2911
3083
|
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
3084
|
+
.pr-helper-file-menu-trigger {
|
|
3085
|
+
display: inline-flex;
|
|
3086
|
+
align-items: center;
|
|
3087
|
+
justify-content: center;
|
|
3088
|
+
width: 24px;
|
|
3089
|
+
height: 24px;
|
|
3090
|
+
padding: 0;
|
|
3091
|
+
border: 0;
|
|
3092
|
+
border-radius: 6px;
|
|
3093
|
+
background: transparent;
|
|
3094
|
+
color: var(--color-fg-muted, #57606a);
|
|
3095
|
+
cursor: pointer;
|
|
3096
|
+
}
|
|
3097
|
+
.pr-helper-file-menu-trigger:hover,
|
|
3098
|
+
.pr-helper-file-menu-trigger[aria-expanded='true'] { background: rgba(31, 35, 40, 0.07); }
|
|
3099
|
+
.pr-helper-file-menu-trigger:focus-visible { outline: 2px solid #9333ea; outline-offset: -2px; }
|
|
2916
3100
|
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
3101
|
+
/* The same panel as the selection popover and a card's Ask Buddy menu. */
|
|
3102
|
+
.pr-helper-file-menu {
|
|
3103
|
+
position: absolute;
|
|
3104
|
+
top: 28px;
|
|
3105
|
+
right: 0;
|
|
3106
|
+
z-index: 5;
|
|
3107
|
+
min-width: 160px;
|
|
3108
|
+
padding: 4px;
|
|
3109
|
+
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
3110
|
+
border-radius: 8px;
|
|
3111
|
+
background: #ffffff;
|
|
3112
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
|
|
3113
|
+
}
|
|
3114
|
+
.pr-helper-file-menu .pr-helper-action-btn {
|
|
3115
|
+
display: block;
|
|
3116
|
+
width: 100%;
|
|
3117
|
+
padding: 7px 10px;
|
|
3118
|
+
border: 0;
|
|
3119
|
+
border-radius: 6px;
|
|
3120
|
+
background: transparent;
|
|
3121
|
+
color: var(--color-fg-default, #24292f);
|
|
3122
|
+
font-family: inherit;
|
|
3123
|
+
font-size: 12px;
|
|
3124
|
+
text-align: left;
|
|
3125
|
+
cursor: pointer;
|
|
3126
|
+
}
|
|
3127
|
+
.pr-helper-file-menu .pr-helper-action-btn:hover:not([disabled]) { background: rgba(147, 51, 234, 0.1); color: #9333ea; }
|
|
3128
|
+
.pr-helper-file-menu .pr-helper-action-btn:focus-visible { outline: 2px solid #9333ea; outline-offset: -2px; }
|
|
3129
|
+
.pr-helper-file-menu .pr-helper-action-btn[disabled] { opacity: 0.5; cursor: default; }
|
|
3130
|
+
|
|
3131
|
+
/* The running state keeps the tray: "Analysing…" and Cancel float over the row's text as one
|
|
3132
|
+
panel, and #fbf7fe is the row's 4% purple hover tint composited over white. */
|
|
3133
|
+
.pr-helper-file-actions-running {
|
|
2922
3134
|
background: #ffffff;
|
|
2923
3135
|
padding: 4px 6px;
|
|
2924
3136
|
border: 1px solid rgba(147, 51, 234, 0.25);
|
|
2925
3137
|
border-radius: 8px;
|
|
2926
3138
|
box-shadow: 0 2px 6px rgba(31, 35, 40, 0.10);
|
|
2927
|
-
/* The tray's default `stretch` left the "Analysing…" label top-aligned in a box the taller
|
|
2928
|
-
Cancel button had grown, so the two read as being on different lines. */
|
|
2929
3139
|
align-items: center;
|
|
2930
3140
|
}
|
|
2931
|
-
|
|
2932
|
-
.pr-helper-file-item:hover .pr-helper-file-actions {
|
|
2933
|
-
opacity: 1;
|
|
2934
|
-
pointer-events: auto;
|
|
2935
|
-
background: #fbf7fe;
|
|
2936
|
-
}
|
|
3141
|
+
.pr-helper-file-item:hover .pr-helper-file-actions-running { background: #fbf7fe; }
|
|
2937
3142
|
|
|
2938
3143
|
/* Opts out of the hover gate above, and must: this is the only indication that a follow-up is
|
|
2939
3144
|
running and the only way to stop it, so a version of it you have to hover to find would leave
|
|
@@ -3365,7 +3570,9 @@
|
|
|
3365
3570
|
border: 2px solid #9333ea;
|
|
3366
3571
|
border-radius: 6px;
|
|
3367
3572
|
pointer-events: none;
|
|
3368
|
-
|
|
3573
|
+
/* Below every floating control (Save for later is 999996, the overlay 999997): a decoration that
|
|
3574
|
+
shared a number painted its border across Save for later. Still above ordinary page content. */
|
|
3575
|
+
z-index: 999995;
|
|
3369
3576
|
/* No dimming wash behind this. It used to carry `box-shadow: 0 0 0 2000px rgba(147,51,234,
|
|
3370
3577
|
0.04)` — a full-page purple tint over everything outside the box, painted above all of
|
|
3371
3578
|
GitHub's own content. At 4% it read as subtle until something saturated sat under it:
|
|
@@ -3912,8 +4119,17 @@
|
|
|
3912
4119
|
flex-direction: column;
|
|
3913
4120
|
min-width: 220px;
|
|
3914
4121
|
padding: 4px;
|
|
4122
|
+
/* With the saved prompts the list is about 375px. position() keeps it inside the window, but a
|
|
4123
|
+
window shorter than the list would cut it off, so there it scrolls instead. 16px is the two
|
|
4124
|
+
8px viewport margins position() leaves. */
|
|
4125
|
+
max-height: calc(100vh - 16px);
|
|
4126
|
+
overflow-y: auto;
|
|
4127
|
+
box-sizing: border-box;
|
|
3915
4128
|
}
|
|
3916
4129
|
|
|
4130
|
+
/* Scrolled, not squashed: a flex column shrinks its items to fit a capped height. */
|
|
4131
|
+
.pr-helper-selection-popover-expanded .pr-helper-selection-menu > * { flex-shrink: 0; }
|
|
4132
|
+
|
|
3917
4133
|
.pr-helper-selection-menu-item {
|
|
3918
4134
|
padding: 7px 10px;
|
|
3919
4135
|
border: none;
|