@youtyan/code-viewer 0.1.43 → 0.1.44
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/dist/code-viewer.js +22 -0
- package/package.json +1 -1
- package/web/app.js +233 -5
- package/web/index.html +1 -0
- package/web/style.css +89 -1
package/dist/code-viewer.js
CHANGED
|
@@ -633,6 +633,27 @@ function refCommits(cwd, query = "", max = DEFAULT_REF_COMMIT_LIMIT) {
|
|
|
633
633
|
]);
|
|
634
634
|
return mergeCommitResults(limit, hashMatches, subjectMatches, authorMatches);
|
|
635
635
|
}
|
|
636
|
+
function parseRemoteWebUrl(remote) {
|
|
637
|
+
const raw = (remote || "").trim();
|
|
638
|
+
if (!raw)
|
|
639
|
+
return null;
|
|
640
|
+
const sshShorthand = /^[\w.-]+@([\w.-]+):(.+?)(?:\.git)?\/?$/.exec(raw);
|
|
641
|
+
if (sshShorthand)
|
|
642
|
+
return `https://${sshShorthand[1]}/${sshShorthand[2]}`;
|
|
643
|
+
const sshUrl = /^ssh:\/\/(?:[\w.-]+@)?([\w.-]+)(?::\d+)?\/(.+?)(?:\.git)?\/?$/.exec(raw);
|
|
644
|
+
if (sshUrl)
|
|
645
|
+
return `https://${sshUrl[1]}/${sshUrl[2]}`;
|
|
646
|
+
const httpUrl = /^https?:\/\/([\w.-]+)\/(.+?)(?:\.git)?\/?$/.exec(raw);
|
|
647
|
+
if (httpUrl)
|
|
648
|
+
return `https://${httpUrl[1]}/${httpUrl[2]}`;
|
|
649
|
+
return null;
|
|
650
|
+
}
|
|
651
|
+
function remoteWebUrl(cwd) {
|
|
652
|
+
const res = run(["git", "remote", "get-url", "origin"], cwd);
|
|
653
|
+
if (res.code !== 0)
|
|
654
|
+
return null;
|
|
655
|
+
return parseRemoteWebUrl(res.stdout.trim());
|
|
656
|
+
}
|
|
636
657
|
function parseHistoryLog(stdout) {
|
|
637
658
|
const parts = stdout.split("\x00");
|
|
638
659
|
const commits = [];
|
|
@@ -3104,6 +3125,7 @@ function handleTree(url) {
|
|
|
3104
3125
|
function handleSettings() {
|
|
3105
3126
|
return json({
|
|
3106
3127
|
project: basename2(cwd),
|
|
3128
|
+
repo_web_url: remoteWebUrl(cwd),
|
|
3107
3129
|
scope: {
|
|
3108
3130
|
omit_dirs_effective: scopeOmitDirNames,
|
|
3109
3131
|
omit_dirs_built_in: DEFAULT_WORKTREE_OMIT_DIR_NAMES,
|
package/package.json
CHANGED
package/web/app.js
CHANGED
|
@@ -7698,6 +7698,114 @@ ${frontmatter.yaml}
|
|
|
7698
7698
|
};
|
|
7699
7699
|
}
|
|
7700
7700
|
|
|
7701
|
+
// web-src/views/diff-line-select.ts
|
|
7702
|
+
var SELECTED_CLASS = "gdp-diff-line-selected";
|
|
7703
|
+
function cardPath(el) {
|
|
7704
|
+
return el.closest(".gdp-file-shell[data-path]")?.dataset.path || "";
|
|
7705
|
+
}
|
|
7706
|
+
function afterLineFromCell(cell) {
|
|
7707
|
+
const sideCell = cell.closest("td.d2h-code-side-linenumber");
|
|
7708
|
+
if (sideCell) {
|
|
7709
|
+
const side = sideCell.closest(".d2h-file-side-diff");
|
|
7710
|
+
const wrapper = sideCell.closest(".d2h-file-wrapper");
|
|
7711
|
+
if (!side || !wrapper)
|
|
7712
|
+
return null;
|
|
7713
|
+
const sides = wrapper.querySelectorAll(".d2h-file-side-diff");
|
|
7714
|
+
if (sides.length < 2 || side !== sides[1])
|
|
7715
|
+
return null;
|
|
7716
|
+
const line2 = Number((sideCell.textContent || "").trim());
|
|
7717
|
+
return Number.isInteger(line2) && line2 > 0 ? line2 : null;
|
|
7718
|
+
}
|
|
7719
|
+
const numCell = cell.closest("td.d2h-code-linenumber");
|
|
7720
|
+
if (!numCell)
|
|
7721
|
+
return null;
|
|
7722
|
+
const raw = (numCell.querySelector(".line-num2")?.textContent || "").trim();
|
|
7723
|
+
const line = Number(raw);
|
|
7724
|
+
return Number.isInteger(line) && line > 0 ? line : null;
|
|
7725
|
+
}
|
|
7726
|
+
function rowsWithAfterLines(card) {
|
|
7727
|
+
const out = [];
|
|
7728
|
+
card.querySelectorAll("table.d2h-diff-table tr").forEach((row) => {
|
|
7729
|
+
const cell = row.querySelector("td.d2h-code-linenumber, td.d2h-code-side-linenumber");
|
|
7730
|
+
if (!cell)
|
|
7731
|
+
return;
|
|
7732
|
+
const line = afterLineFromCell(cell);
|
|
7733
|
+
if (line !== null)
|
|
7734
|
+
out.push({ row, line });
|
|
7735
|
+
});
|
|
7736
|
+
return out;
|
|
7737
|
+
}
|
|
7738
|
+
function createDiffLineSelect(deps) {
|
|
7739
|
+
let drag = null;
|
|
7740
|
+
let selection = null;
|
|
7741
|
+
function clearHighlights() {
|
|
7742
|
+
document.querySelectorAll(`.${SELECTED_CLASS}`).forEach((row) => {
|
|
7743
|
+
row.classList.remove(SELECTED_CLASS);
|
|
7744
|
+
});
|
|
7745
|
+
}
|
|
7746
|
+
function applySelection(next) {
|
|
7747
|
+
selection = next;
|
|
7748
|
+
clearHighlights();
|
|
7749
|
+
if (!next) {
|
|
7750
|
+
deps.pill.hide();
|
|
7751
|
+
return;
|
|
7752
|
+
}
|
|
7753
|
+
const start = Math.min(next.start, next.end);
|
|
7754
|
+
const end = Math.max(next.start, next.end);
|
|
7755
|
+
const card = document.querySelector(`.gdp-file-shell[data-path="${CSS.escape(next.path)}"]`);
|
|
7756
|
+
if (card) {
|
|
7757
|
+
for (const item of rowsWithAfterLines(card)) {
|
|
7758
|
+
if (item.line >= start && item.line <= end)
|
|
7759
|
+
item.row.classList.add(SELECTED_CLASS);
|
|
7760
|
+
}
|
|
7761
|
+
}
|
|
7762
|
+
deps.pill.show(next.path, start, end);
|
|
7763
|
+
}
|
|
7764
|
+
function clear() {
|
|
7765
|
+
drag = null;
|
|
7766
|
+
applySelection(null);
|
|
7767
|
+
}
|
|
7768
|
+
const diff = document.querySelector("#diff");
|
|
7769
|
+
if (!diff)
|
|
7770
|
+
return { clear };
|
|
7771
|
+
diff.addEventListener("mousedown", (e2) => {
|
|
7772
|
+
const target = e2.target;
|
|
7773
|
+
const cell = target.closest("td.d2h-code-linenumber, td.d2h-code-side-linenumber");
|
|
7774
|
+
if (!cell)
|
|
7775
|
+
return;
|
|
7776
|
+
const line = afterLineFromCell(cell);
|
|
7777
|
+
const path = cardPath(cell);
|
|
7778
|
+
if (line === null || !path) {
|
|
7779
|
+
if (selection)
|
|
7780
|
+
clear();
|
|
7781
|
+
return;
|
|
7782
|
+
}
|
|
7783
|
+
e2.preventDefault();
|
|
7784
|
+
drag = { path, start: line };
|
|
7785
|
+
applySelection({ path, start: line, end: line });
|
|
7786
|
+
});
|
|
7787
|
+
diff.addEventListener("mouseover", (e2) => {
|
|
7788
|
+
if (!drag)
|
|
7789
|
+
return;
|
|
7790
|
+
const target = e2.target;
|
|
7791
|
+
const cell = target.closest("td.d2h-code-linenumber, td.d2h-code-side-linenumber");
|
|
7792
|
+
if (!cell || cardPath(cell) !== drag.path)
|
|
7793
|
+
return;
|
|
7794
|
+
const line = afterLineFromCell(cell);
|
|
7795
|
+
if (line === null)
|
|
7796
|
+
return;
|
|
7797
|
+
applySelection({ path: drag.path, start: drag.start, end: line });
|
|
7798
|
+
});
|
|
7799
|
+
document.addEventListener("mouseup", () => {
|
|
7800
|
+
drag = null;
|
|
7801
|
+
});
|
|
7802
|
+
document.addEventListener("keydown", (e2) => {
|
|
7803
|
+
if (e2.key === "Escape" && selection && !drag)
|
|
7804
|
+
clear();
|
|
7805
|
+
});
|
|
7806
|
+
return { clear };
|
|
7807
|
+
}
|
|
7808
|
+
|
|
7701
7809
|
// web-src/core/file-path-copy.ts
|
|
7702
7810
|
function filePathClipboardText(path) {
|
|
7703
7811
|
return path || "";
|
|
@@ -7708,6 +7816,13 @@ ${frontmatter.yaml}
|
|
|
7708
7816
|
const parts = path.split("/").filter(Boolean);
|
|
7709
7817
|
return parts[parts.length - 1] || "";
|
|
7710
7818
|
}
|
|
7819
|
+
function fileReferenceClipboardText(path, start, end) {
|
|
7820
|
+
if (!path)
|
|
7821
|
+
return "";
|
|
7822
|
+
const a2 = Math.max(1, Math.floor(Math.min(start, end)));
|
|
7823
|
+
const b2 = Math.max(1, Math.floor(Math.max(start, end)));
|
|
7824
|
+
return a2 === b2 ? `@${path}#${a2}` : `@${path}#${a2}-${b2}`;
|
|
7825
|
+
}
|
|
7711
7826
|
|
|
7712
7827
|
// web-src/core/ws-highlight.ts
|
|
7713
7828
|
function isWhitespaceOnlyInlineHighlight(text2) {
|
|
@@ -9769,6 +9884,76 @@ ${frontmatter.yaml}
|
|
|
9769
9884
|
return { setupHunkExpand };
|
|
9770
9885
|
}
|
|
9771
9886
|
|
|
9887
|
+
// web-src/views/line-ref-pill.ts
|
|
9888
|
+
var COPY_ICON = '<svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true" fill="currentColor">' + '<path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"/>' + '<path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"/>' + "</svg>";
|
|
9889
|
+
var CHECK_ICON = '<svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true" fill="currentColor">' + '<path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/>' + "</svg>";
|
|
9890
|
+
function escapeHtml2(value) {
|
|
9891
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
9892
|
+
}
|
|
9893
|
+
function createLineRefPill() {
|
|
9894
|
+
const pill = document.createElement("button");
|
|
9895
|
+
pill.id = "line-ref-pill";
|
|
9896
|
+
pill.type = "button";
|
|
9897
|
+
pill.title = "選択行の参照をコピー(Claude Code / Codex に貼り付け用)";
|
|
9898
|
+
pill.hidden = true;
|
|
9899
|
+
document.body.appendChild(pill);
|
|
9900
|
+
let refText = "";
|
|
9901
|
+
let feedbackTimer = null;
|
|
9902
|
+
function render(state) {
|
|
9903
|
+
pill.classList.toggle("copied", state === "copied");
|
|
9904
|
+
if (state === "copied") {
|
|
9905
|
+
pill.innerHTML = `${CHECK_ICON}<span class="lrp-label">Copied!</span>`;
|
|
9906
|
+
return;
|
|
9907
|
+
}
|
|
9908
|
+
if (state === "failed") {
|
|
9909
|
+
pill.innerHTML = `${COPY_ICON}<span class="lrp-label">copy failed</span>`;
|
|
9910
|
+
return;
|
|
9911
|
+
}
|
|
9912
|
+
pill.innerHTML = `${COPY_ICON}<span class="lrp-label">Copy</span>` + `<span class="lrp-ref">${escapeHtml2(refText)}</span>`;
|
|
9913
|
+
}
|
|
9914
|
+
pill.addEventListener("click", async () => {
|
|
9915
|
+
if (!refText)
|
|
9916
|
+
return;
|
|
9917
|
+
try {
|
|
9918
|
+
await navigator.clipboard.writeText(refText);
|
|
9919
|
+
render("copied");
|
|
9920
|
+
} catch {
|
|
9921
|
+
render("failed");
|
|
9922
|
+
}
|
|
9923
|
+
if (feedbackTimer)
|
|
9924
|
+
clearTimeout(feedbackTimer);
|
|
9925
|
+
feedbackTimer = setTimeout(() => {
|
|
9926
|
+
feedbackTimer = null;
|
|
9927
|
+
if (!pill.hidden)
|
|
9928
|
+
render("ready");
|
|
9929
|
+
}, 1200);
|
|
9930
|
+
});
|
|
9931
|
+
return {
|
|
9932
|
+
show(path, start, end) {
|
|
9933
|
+
const next = fileReferenceClipboardText(path, start, end);
|
|
9934
|
+
if (!next)
|
|
9935
|
+
return;
|
|
9936
|
+
const changed = next !== refText;
|
|
9937
|
+
refText = next;
|
|
9938
|
+
if (feedbackTimer) {
|
|
9939
|
+
clearTimeout(feedbackTimer);
|
|
9940
|
+
feedbackTimer = null;
|
|
9941
|
+
}
|
|
9942
|
+
render("ready");
|
|
9943
|
+
if (pill.hidden || changed) {
|
|
9944
|
+
pill.classList.remove("pop");
|
|
9945
|
+
pill.offsetWidth;
|
|
9946
|
+
pill.classList.add("pop");
|
|
9947
|
+
}
|
|
9948
|
+
pill.hidden = false;
|
|
9949
|
+
},
|
|
9950
|
+
hide() {
|
|
9951
|
+
refText = "";
|
|
9952
|
+
pill.hidden = true;
|
|
9953
|
+
}
|
|
9954
|
+
};
|
|
9955
|
+
}
|
|
9956
|
+
|
|
9772
9957
|
// web-src/views/ref-picker.ts
|
|
9773
9958
|
function createRefPicker(deps) {
|
|
9774
9959
|
function wireRefSelectorInput(input, onPick) {
|
|
@@ -15126,6 +15311,11 @@ ${frontmatter.yaml}
|
|
|
15126
15311
|
return null;
|
|
15127
15312
|
const settings = await res.json();
|
|
15128
15313
|
setProjectName(settings.project || "");
|
|
15314
|
+
const repoLink = document.querySelector("#repo-web-link");
|
|
15315
|
+
if (repoLink && settings.repo_web_url) {
|
|
15316
|
+
repoLink.href = settings.repo_web_url;
|
|
15317
|
+
repoLink.hidden = false;
|
|
15318
|
+
}
|
|
15129
15319
|
SERVER_SCOPE_OMIT_DIRS_DEFAULT = normalizeScopeOmitDirs(settings.scope.omit_dirs_effective);
|
|
15130
15320
|
SERVER_SCOPE_EXCLUDE_NAMES_DEFAULT = normalizeScopeExcludeNames(settings.scope.exclude_names_effective);
|
|
15131
15321
|
return settings;
|
|
@@ -15164,6 +15354,19 @@ ${frontmatter.yaml}
|
|
|
15164
15354
|
let highlightConfigured = false;
|
|
15165
15355
|
let PROJECT_NAME = "";
|
|
15166
15356
|
let REPO_SIDEBAR_REF = null;
|
|
15357
|
+
const LINE_REF_PILL = createLineRefPill();
|
|
15358
|
+
const DIFF_LINE_SELECT = createDiffLineSelect({ pill: LINE_REF_PILL });
|
|
15359
|
+
function syncLineRefPill() {
|
|
15360
|
+
const route = STATE.route;
|
|
15361
|
+
if (route.screen === "diff")
|
|
15362
|
+
return;
|
|
15363
|
+
DIFF_LINE_SELECT.clear();
|
|
15364
|
+
if (route.screen === "file" && route.line) {
|
|
15365
|
+
const start = typeof route.line === "number" ? route.line : route.line.start;
|
|
15366
|
+
const end = typeof route.line === "number" ? route.line : route.line.end;
|
|
15367
|
+
LINE_REF_PILL.show(route.path, start, end);
|
|
15368
|
+
}
|
|
15369
|
+
}
|
|
15167
15370
|
const SIDEBAR = createSidebar({
|
|
15168
15371
|
$,
|
|
15169
15372
|
$$,
|
|
@@ -15553,7 +15756,7 @@ ${frontmatter.yaml}
|
|
|
15553
15756
|
throw e2;
|
|
15554
15757
|
});
|
|
15555
15758
|
}
|
|
15556
|
-
function
|
|
15759
|
+
function escapeHtml3(s2) {
|
|
15557
15760
|
return String(s2 == null ? "" : s2).replace(/[&<>"']/g, (c2) => ({
|
|
15558
15761
|
"&": "&",
|
|
15559
15762
|
"<": "<",
|
|
@@ -15571,6 +15774,19 @@ ${frontmatter.yaml}
|
|
|
15571
15774
|
to: STATE.to || DEFAULT_RANGE.to
|
|
15572
15775
|
};
|
|
15573
15776
|
}
|
|
15777
|
+
let preHistoryRange = null;
|
|
15778
|
+
function parkRangeForHistory() {
|
|
15779
|
+
if (preHistoryRange === null)
|
|
15780
|
+
preHistoryRange = { from: STATE.from, to: STATE.to };
|
|
15781
|
+
}
|
|
15782
|
+
function restoreRangeAfterHistory() {
|
|
15783
|
+
if (!preHistoryRange)
|
|
15784
|
+
return;
|
|
15785
|
+
STATE.from = preHistoryRange.from;
|
|
15786
|
+
STATE.to = preHistoryRange.to;
|
|
15787
|
+
preHistoryRange = null;
|
|
15788
|
+
syncRefInputs();
|
|
15789
|
+
}
|
|
15574
15790
|
function repoFileTargetFromRoute() {
|
|
15575
15791
|
return STATE.route.screen === "file" && STATE.route.view === "blob" ? STATE.route.ref : null;
|
|
15576
15792
|
}
|
|
@@ -15601,6 +15817,7 @@ ${frontmatter.yaml}
|
|
|
15601
15817
|
else
|
|
15602
15818
|
history.pushState(state, "", url);
|
|
15603
15819
|
syncHeaderMenu();
|
|
15820
|
+
syncLineRefPill();
|
|
15604
15821
|
}
|
|
15605
15822
|
function setPageMode() {
|
|
15606
15823
|
document.body.classList.toggle("gdp-file-detail-page", STATE.route.screen === "file");
|
|
@@ -15633,7 +15850,10 @@ ${frontmatter.yaml}
|
|
|
15633
15850
|
});
|
|
15634
15851
|
}
|
|
15635
15852
|
if (link2.dataset.route === "diff") {
|
|
15636
|
-
link2.href = buildRoute({
|
|
15853
|
+
link2.href = buildRoute({
|
|
15854
|
+
screen: "diff",
|
|
15855
|
+
range: preHistoryRange ?? currentRange()
|
|
15856
|
+
});
|
|
15637
15857
|
}
|
|
15638
15858
|
if (link2.dataset.route === "history") {
|
|
15639
15859
|
link2.href = buildRoute({
|
|
@@ -15763,7 +15983,7 @@ ${frontmatter.yaml}
|
|
|
15763
15983
|
STATE,
|
|
15764
15984
|
setRoute,
|
|
15765
15985
|
currentRange,
|
|
15766
|
-
escapeHtml:
|
|
15986
|
+
escapeHtml: escapeHtml3,
|
|
15767
15987
|
trackLoad,
|
|
15768
15988
|
diffCardSelector,
|
|
15769
15989
|
getHljs,
|
|
@@ -16169,10 +16389,12 @@ ${frontmatter.yaml}
|
|
|
16169
16389
|
setStatus("live");
|
|
16170
16390
|
applySourceRouteToShell();
|
|
16171
16391
|
} else if (STATE.route.screen === "history") {
|
|
16392
|
+
parkRangeForHistory();
|
|
16172
16393
|
setStatus("live");
|
|
16173
16394
|
HISTORY_VIEW.enterHistory();
|
|
16174
16395
|
} else
|
|
16175
16396
|
load();
|
|
16397
|
+
syncLineRefPill();
|
|
16176
16398
|
});
|
|
16177
16399
|
function syncRefInputs() {
|
|
16178
16400
|
const fi = $("#ref-from"), ti = $("#ref-to");
|
|
@@ -16182,6 +16404,7 @@ ${frontmatter.yaml}
|
|
|
16182
16404
|
ti.value = STATE.to;
|
|
16183
16405
|
}
|
|
16184
16406
|
function setRange(from, to) {
|
|
16407
|
+
preHistoryRange = null;
|
|
16185
16408
|
STATE.from = from || "";
|
|
16186
16409
|
STATE.to = to || "";
|
|
16187
16410
|
localStorage.setItem("gdp:from", STATE.from);
|
|
@@ -16208,7 +16431,7 @@ ${frontmatter.yaml}
|
|
|
16208
16431
|
syncHeaderMenu();
|
|
16209
16432
|
const HISTORY_VIEW = createHistoryView({
|
|
16210
16433
|
$,
|
|
16211
|
-
escapeHtml:
|
|
16434
|
+
escapeHtml: escapeHtml3,
|
|
16212
16435
|
getRoute: () => STATE.route,
|
|
16213
16436
|
setRoute,
|
|
16214
16437
|
applyCommitRange: (range) => {
|
|
@@ -16237,7 +16460,7 @@ ${frontmatter.yaml}
|
|
|
16237
16460
|
});
|
|
16238
16461
|
const REF_PICKER = createRefPicker({
|
|
16239
16462
|
$,
|
|
16240
|
-
escapeHtml:
|
|
16463
|
+
escapeHtml: escapeHtml3,
|
|
16241
16464
|
currentRange,
|
|
16242
16465
|
setRange,
|
|
16243
16466
|
setRoute,
|
|
@@ -16256,6 +16479,9 @@ ${frontmatter.yaml}
|
|
|
16256
16479
|
}
|
|
16257
16480
|
$("#ref-reset").addEventListener("click", () => setRange("HEAD", "worktree"));
|
|
16258
16481
|
function applyRouteFromLocation() {
|
|
16482
|
+
if (STATE.route.screen === "history" && window.location.pathname !== "/history") {
|
|
16483
|
+
restoreRangeAfterHistory();
|
|
16484
|
+
}
|
|
16259
16485
|
const parsedRoute = parseRoute(window.location.pathname, window.location.search, currentRange());
|
|
16260
16486
|
STATE.route = parsedRoute.screen === "unknown" ? { screen: "diff", range: parsedRoute.range } : parsedRoute;
|
|
16261
16487
|
STATE.from = STATE.route.range.from;
|
|
@@ -16265,6 +16491,7 @@ ${frontmatter.yaml}
|
|
|
16265
16491
|
ANNOTATIONS_UI?.restoreSessionFromUrl();
|
|
16266
16492
|
syncRefInputs();
|
|
16267
16493
|
syncHeaderMenu();
|
|
16494
|
+
syncLineRefPill();
|
|
16268
16495
|
if (STATE.route.screen === "help") {
|
|
16269
16496
|
cancelActiveSourceLoad("navigation");
|
|
16270
16497
|
setPageMode();
|
|
@@ -16280,6 +16507,7 @@ ${frontmatter.yaml}
|
|
|
16280
16507
|
return;
|
|
16281
16508
|
}
|
|
16282
16509
|
if (STATE.route.screen === "history") {
|
|
16510
|
+
parkRangeForHistory();
|
|
16283
16511
|
cancelActiveSourceLoad("navigation");
|
|
16284
16512
|
setPageMode();
|
|
16285
16513
|
removeStandaloneSource();
|
package/web/index.html
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
<button id="viewer-settings" class="global-icon-action" title="viewer settings" aria-label="viewer settings"></button>
|
|
34
34
|
<button id="theme" title="toggle theme">🌗</button>
|
|
35
35
|
<span id="status" class="status"></span>
|
|
36
|
+
<a id="repo-web-link" class="global-help-link" href="#" target="_blank" rel="noopener" hidden>GitHub</a>
|
|
36
37
|
<a class="global-help-link" data-route="help" href="/help">Help</a>
|
|
37
38
|
<span class="product-label" aria-hidden="true">code viewer</span>
|
|
38
39
|
</div>
|
package/web/style.css
CHANGED
|
@@ -926,6 +926,11 @@ body.gdp-history-page.gdp-sidebar-hidden main#content {
|
|
|
926
926
|
body.gdp-history-page #sidebar-resizer {
|
|
927
927
|
left: calc(var(--history-w) + var(--sidebar-w) - 4px);
|
|
928
928
|
}
|
|
929
|
+
/* The history screen drives its diff range from the commit list; the topbar
|
|
930
|
+
from/to pickers belong to the Diff Viewer and are hidden here. */
|
|
931
|
+
body.gdp-history-page #topbar .ref-pickers {
|
|
932
|
+
display: none;
|
|
933
|
+
}
|
|
929
934
|
#history-panel[hidden] {
|
|
930
935
|
display: none !important;
|
|
931
936
|
}
|
|
@@ -1801,7 +1806,10 @@ body.gdp-help-page #content {
|
|
|
1801
1806
|
|
|
1802
1807
|
#diff > *:first-child { margin-top: 0; }
|
|
1803
1808
|
|
|
1804
|
-
|
|
1809
|
+
/* Scroll-past-end spacer so the sidebar can align the last diff file to the
|
|
1810
|
+
top of the viewport. Not wanted on the history screen, where small
|
|
1811
|
+
single-commit diffs would gain a screenful of dead scroll space. */
|
|
1812
|
+
body:not(.gdp-file-detail-page):not(.gdp-history-page) #diff::after {
|
|
1805
1813
|
content: "";
|
|
1806
1814
|
display: block;
|
|
1807
1815
|
height: calc(100vh - var(--chrome-h) - 40px);
|
|
@@ -2071,6 +2079,86 @@ table.d2h-diff-table tr.gdp-diff-line-target .d2h-code-line-ctn {
|
|
|
2071
2079
|
table.d2h-diff-table tr.gdp-diff-line-target > td:first-child {
|
|
2072
2080
|
box-shadow: inset 3px 0 0 var(--line-hit-border), inset -1px 0 0 var(--border-muted);
|
|
2073
2081
|
}
|
|
2082
|
+
|
|
2083
|
+
/* After-side drag selection (diff screen) — same yellow as the file view. */
|
|
2084
|
+
table.d2h-diff-table tr.gdp-diff-line-selected > td,
|
|
2085
|
+
table.d2h-diff-table tr.gdp-diff-line-selected .d2h-code-line,
|
|
2086
|
+
table.d2h-diff-table tr.gdp-diff-line-selected .d2h-code-side-line,
|
|
2087
|
+
table.d2h-diff-table tr.gdp-diff-line-selected .d2h-code-line-ctn {
|
|
2088
|
+
background: var(--line-hit-bg) !important;
|
|
2089
|
+
background-color: var(--line-hit-bg) !important;
|
|
2090
|
+
}
|
|
2091
|
+
table.d2h-diff-table tr.gdp-diff-line-selected > td:first-child {
|
|
2092
|
+
box-shadow: inset 3px 0 0 var(--line-hit-border), inset -1px 0 0 var(--border-muted);
|
|
2093
|
+
}
|
|
2094
|
+
table.d2h-diff-table td.d2h-code-linenumber,
|
|
2095
|
+
table.d2h-diff-table td.d2h-code-side-linenumber {
|
|
2096
|
+
cursor: pointer;
|
|
2097
|
+
user-select: none;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
/* Floating "copy @path#start-end" pill shown while lines are selected. */
|
|
2101
|
+
#line-ref-pill {
|
|
2102
|
+
position: fixed;
|
|
2103
|
+
left: 50%;
|
|
2104
|
+
bottom: 24px;
|
|
2105
|
+
transform: translateX(-50%);
|
|
2106
|
+
z-index: 400;
|
|
2107
|
+
display: inline-flex;
|
|
2108
|
+
align-items: center;
|
|
2109
|
+
gap: 8px;
|
|
2110
|
+
max-width: min(680px, calc(100vw - 48px));
|
|
2111
|
+
white-space: nowrap;
|
|
2112
|
+
padding: 9px 16px;
|
|
2113
|
+
border: 1px solid var(--accent);
|
|
2114
|
+
border-radius: 999px;
|
|
2115
|
+
background: var(--accent);
|
|
2116
|
+
color: #fff;
|
|
2117
|
+
font: inherit;
|
|
2118
|
+
font-size: 13px;
|
|
2119
|
+
font-weight: 600;
|
|
2120
|
+
cursor: pointer;
|
|
2121
|
+
box-shadow: 0 8px 28px rgba(31, 35, 40, 0.35);
|
|
2122
|
+
}
|
|
2123
|
+
#line-ref-pill:hover {
|
|
2124
|
+
filter: brightness(1.1);
|
|
2125
|
+
}
|
|
2126
|
+
#line-ref-pill svg {
|
|
2127
|
+
flex: 0 0 auto;
|
|
2128
|
+
}
|
|
2129
|
+
#line-ref-pill .lrp-label {
|
|
2130
|
+
flex: 0 0 auto;
|
|
2131
|
+
}
|
|
2132
|
+
#line-ref-pill .lrp-ref {
|
|
2133
|
+
overflow: hidden;
|
|
2134
|
+
text-overflow: ellipsis;
|
|
2135
|
+
padding: 2px 8px;
|
|
2136
|
+
border-radius: 6px;
|
|
2137
|
+
background: rgba(255, 255, 255, 0.18);
|
|
2138
|
+
font-family: "Monaspace Neon", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
|
|
2139
|
+
font-size: 12px;
|
|
2140
|
+
font-weight: 400;
|
|
2141
|
+
}
|
|
2142
|
+
#line-ref-pill.copied {
|
|
2143
|
+
background: var(--success, #2ea043);
|
|
2144
|
+
border-color: var(--success, #2ea043);
|
|
2145
|
+
}
|
|
2146
|
+
#line-ref-pill.pop {
|
|
2147
|
+
animation: lrp-pop 0.22s ease-out;
|
|
2148
|
+
}
|
|
2149
|
+
@keyframes lrp-pop {
|
|
2150
|
+
0% {
|
|
2151
|
+
transform: translateX(-50%) translateY(14px) scale(0.92);
|
|
2152
|
+
opacity: 0;
|
|
2153
|
+
}
|
|
2154
|
+
100% {
|
|
2155
|
+
transform: translateX(-50%) translateY(0) scale(1);
|
|
2156
|
+
opacity: 1;
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
#line-ref-pill[hidden] {
|
|
2160
|
+
display: none;
|
|
2161
|
+
}
|
|
2074
2162
|
/* Stack height = number of buttons * 20px. With 1 button = 20px row,
|
|
2075
2163
|
* with 2 (↑+↓) = 40px row, matching GitHub. */
|
|
2076
2164
|
.gdp-expand-stack {
|