VIDRAFT Claude Opus 5 commited on
Commit 路
39ebfa8
1
Parent(s): ca1ba69
Keep the detail overlay off the copy button
Browse filesThe overlay opened aligned to the row's left edge - exactly where the structure and its
copy button sit - so hovering a row buried the control the reader was reaching for. It now
anchors to the right of the row, leaving the structure column clear, and carries its own
copy button so the full string is available from the panel that is already open.
The panel accepts clicks now rather than being click-through, which it has to be to hold a
button, and a short grace period on leaving a row means moving the pointer into the panel
does not dismiss it first.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- index.html +29 -16
index.html
CHANGED
|
@@ -75,7 +75,7 @@
|
|
| 75 |
|
| 76 |
#ov{position:fixed;z-index:50;display:none;width:340px;background:#fff;
|
| 77 |
border:1px solid var(--line);border-radius:14px;padding:15px 16px;
|
| 78 |
-
box-shadow:0 12px 40px rgba(19,26,38,.18)
|
| 79 |
#ov h4{margin:0 0 2px;font-size:14px;font-weight:800;letter-spacing:-.2px}
|
| 80 |
#ov .oid{font-size:11px;color:var(--muted);font-family:ui-monospace,monospace;margin-bottom:10px}
|
| 81 |
#ov .orow{display:grid;grid-template-columns:60px 1fr 42px;gap:8px;align-items:center;
|
|
@@ -223,7 +223,8 @@
|
|
| 223 |
.lock{color:#93a1b5;font-size:10.5px;margin-top:1px;display:block}
|
| 224 |
#ov .osmi{margin-top:10px;padding:9px 10px;background:#f6f8fc;border:1px solid var(--line);
|
| 225 |
border-radius:8px;font-family:ui-monospace,Menlo,monospace;font-size:10.5px;
|
| 226 |
-
color:#31465e;line-height:1.5;word-break:break-all}
|
|
|
|
| 227 |
.who{color:var(--muted);font-size:12.5px}
|
| 228 |
/* Long model identifiers wrapped onto four lines and made every row three times
|
| 229 |
taller than it needed to be. Truncate; the full value is on the tooltip. */
|
|
@@ -718,23 +719,15 @@ function render(){
|
|
| 718 |
<span class="tot">${f1(e.total)}</span></div></td></tr>`;
|
| 719 |
}).join("") : `<tr><td colspan="11" class="who">${d.empty}</td></tr>`;
|
| 720 |
|
| 721 |
-
$("#rows")
|
| 722 |
-
// without this the click also reaches the row and toggles the overlay
|
| 723 |
-
ev.stopPropagation();
|
| 724 |
-
const v = b.dataset.smi;
|
| 725 |
-
try{ await navigator.clipboard.writeText(v); }
|
| 726 |
-
catch(_){ const ta=document.createElement("textarea"); ta.value=v;
|
| 727 |
-
document.body.appendChild(ta); ta.select(); document.execCommand("copy"); ta.remove(); }
|
| 728 |
-
b.classList.add("done"); b.textContent = "\u2713";
|
| 729 |
-
setTimeout(()=>{ b.classList.remove("done"); b.textContent = "\u29c9"; }, 1200);
|
| 730 |
-
});
|
| 731 |
|
| 732 |
// rows carry their entry so the overlay never has to look anything up again
|
| 733 |
[...document.querySelectorAll("#rows tr")].forEach((tr, i) => {
|
| 734 |
const e = rows[i];
|
| 735 |
if(!e) return;
|
| 736 |
-
tr.onmouseenter = () => showOverlay(e, tr.getBoundingClientRect());
|
| 737 |
-
|
|
|
|
| 738 |
// touch has no hover, so a tap toggles it
|
| 739 |
tr.onclick = () => (OV.style.display === "block" && OV.dataset.id === e.candidate_id)
|
| 740 |
? hideOverlay()
|
|
@@ -935,13 +928,28 @@ function overlayHTML(e){
|
|
| 935 |
? `<div class="oflag">${e.relegate_reason.map(reasonText).join(" / ")}</div>` : "";
|
| 936 |
const who = e.is_anchor ? (e.note||"") : [e.hf_user, e.model_name].filter(Boolean).join(" 路 ");
|
| 937 |
const full = (e.visibility === "public" && e.smiles) ? e.smiles : e.smiles_masked;
|
|
|
|
| 938 |
const smi = e.is_anchor ? ""
|
| 939 |
: `<div class="osmi">${full || ""}`
|
|
|
|
| 940 |
+ (e.visibility === "public" ? "" : `<br>馃敀 ${d.private_full}`) + `</div>`;
|
| 941 |
return `<h4>${e.candidate_id}</h4><div class="oid">${who}${e.skeleton?" 路 "+e.skeleton:""}</div>`
|
| 942 |
+ rows + pred + smi + flag + `<div class="ofoot">${d.ov_foot}</div>`;
|
| 943 |
}
|
| 944 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 945 |
function showOverlay(e, rect){
|
| 946 |
OV.innerHTML = overlayHTML(e);
|
| 947 |
OV.style.display = "block";
|
|
@@ -949,11 +957,16 @@ function showOverlay(e, rect){
|
|
| 949 |
// flip above the row rather than open past the bottom of the window
|
| 950 |
let top = rect.bottom + 8;
|
| 951 |
if(top + h > window.innerHeight - 8) top = Math.max(8, rect.top - h - 8);
|
| 952 |
-
|
|
|
|
|
|
|
| 953 |
OV.style.top = top + "px";
|
| 954 |
-
OV.style.left =
|
|
|
|
| 955 |
}
|
| 956 |
function hideOverlay(){ OV.style.display = "none"; }
|
|
|
|
|
|
|
| 957 |
|
| 958 |
async function load(){
|
| 959 |
try{
|
|
|
|
| 75 |
|
| 76 |
#ov{position:fixed;z-index:50;display:none;width:340px;background:#fff;
|
| 77 |
border:1px solid var(--line);border-radius:14px;padding:15px 16px;
|
| 78 |
+
box-shadow:0 12px 40px rgba(19,26,38,.18)}
|
| 79 |
#ov h4{margin:0 0 2px;font-size:14px;font-weight:800;letter-spacing:-.2px}
|
| 80 |
#ov .oid{font-size:11px;color:var(--muted);font-family:ui-monospace,monospace;margin-bottom:10px}
|
| 81 |
#ov .orow{display:grid;grid-template-columns:60px 1fr 42px;gap:8px;align-items:center;
|
|
|
|
| 223 |
.lock{color:#93a1b5;font-size:10.5px;margin-top:1px;display:block}
|
| 224 |
#ov .osmi{margin-top:10px;padding:9px 10px;background:#f6f8fc;border:1px solid var(--line);
|
| 225 |
border-radius:8px;font-family:ui-monospace,Menlo,monospace;font-size:10.5px;
|
| 226 |
+
color:#31465e;line-height:1.5;word-break:break-all;position:relative}
|
| 227 |
+
#ov .osmi .cp{position:absolute;top:6px;right:6px}
|
| 228 |
.who{color:var(--muted);font-size:12.5px}
|
| 229 |
/* Long model identifiers wrapped onto four lines and made every row three times
|
| 230 |
taller than it needed to be. Truncate; the full value is on the tooltip. */
|
|
|
|
| 719 |
<span class="tot">${f1(e.total)}</span></div></td></tr>`;
|
| 720 |
}).join("") : `<tr><td colspan="11" class="who">${d.empty}</td></tr>`;
|
| 721 |
|
| 722 |
+
wireCopy($("#rows"));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 723 |
|
| 724 |
// rows carry their entry so the overlay never has to look anything up again
|
| 725 |
[...document.querySelectorAll("#rows tr")].forEach((tr, i) => {
|
| 726 |
const e = rows[i];
|
| 727 |
if(!e) return;
|
| 728 |
+
tr.onmouseenter = () => { clearTimeout(OV._t); showOverlay(e, tr.getBoundingClientRect()); };
|
| 729 |
+
// a short grace period, so moving the pointer into the panel does not dismiss it
|
| 730 |
+
tr.onmouseleave = () => { OV._t = setTimeout(hideOverlay, 220); };
|
| 731 |
// touch has no hover, so a tap toggles it
|
| 732 |
tr.onclick = () => (OV.style.display === "block" && OV.dataset.id === e.candidate_id)
|
| 733 |
? hideOverlay()
|
|
|
|
| 928 |
? `<div class="oflag">${e.relegate_reason.map(reasonText).join(" / ")}</div>` : "";
|
| 929 |
const who = e.is_anchor ? (e.note||"") : [e.hf_user, e.model_name].filter(Boolean).join(" 路 ");
|
| 930 |
const full = (e.visibility === "public" && e.smiles) ? e.smiles : e.smiles_masked;
|
| 931 |
+
const canCopy = e.visibility === "public" && e.smiles;
|
| 932 |
const smi = e.is_anchor ? ""
|
| 933 |
: `<div class="osmi">${full || ""}`
|
| 934 |
+
+ (canCopy ? `<button class="cp" data-smi="${e.smiles}" title="${d.copy_smiles}">\u29c9</button>` : "")
|
| 935 |
+ (e.visibility === "public" ? "" : `<br>馃敀 ${d.private_full}`) + `</div>`;
|
| 936 |
return `<h4>${e.candidate_id}</h4><div class="oid">${who}${e.skeleton?" 路 "+e.skeleton:""}</div>`
|
| 937 |
+ rows + pred + smi + flag + `<div class="ofoot">${d.ov_foot}</div>`;
|
| 938 |
}
|
| 939 |
|
| 940 |
+
function wireCopy(root){
|
| 941 |
+
root.querySelectorAll(".cp").forEach(b => b.onclick = async (ev) => {
|
| 942 |
+
// without this the click also reaches the row and toggles the overlay
|
| 943 |
+
ev.stopPropagation();
|
| 944 |
+
const v = b.dataset.smi;
|
| 945 |
+
try{ await navigator.clipboard.writeText(v); }
|
| 946 |
+
catch(_){ const ta=document.createElement("textarea"); ta.value=v;
|
| 947 |
+
document.body.appendChild(ta); ta.select(); document.execCommand("copy"); ta.remove(); }
|
| 948 |
+
b.classList.add("done"); b.textContent = "\u2713";
|
| 949 |
+
setTimeout(()=>{ b.classList.remove("done"); b.textContent = "\u29c9"; }, 1200);
|
| 950 |
+
});
|
| 951 |
+
}
|
| 952 |
+
|
| 953 |
function showOverlay(e, rect){
|
| 954 |
OV.innerHTML = overlayHTML(e);
|
| 955 |
OV.style.display = "block";
|
|
|
|
| 957 |
// flip above the row rather than open past the bottom of the window
|
| 958 |
let top = rect.bottom + 8;
|
| 959 |
if(top + h > window.innerHeight - 8) top = Math.max(8, rect.top - h - 8);
|
| 960 |
+
// anchor to the right of the row: the structure and its copy button live on the left,
|
| 961 |
+
// and opening over them buries the control the reader was reaching for
|
| 962 |
+
let left = Math.max(8, Math.min(rect.right - w, window.innerWidth - w - 12));
|
| 963 |
OV.style.top = top + "px";
|
| 964 |
+
OV.style.left = left + "px";
|
| 965 |
+
wireCopy(OV);
|
| 966 |
}
|
| 967 |
function hideOverlay(){ OV.style.display = "none"; }
|
| 968 |
+
OV.onmouseenter = () => clearTimeout(OV._t);
|
| 969 |
+
OV.onmouseleave = hideOverlay;
|
| 970 |
|
| 971 |
async function load(){
|
| 972 |
try{
|