fix(dashboard): robust shift-mode tracking via mousemove + element highlights

- updateMode() now subscribes to keydown, keyup AND mousemove so the
  body class stays in sync regardless of where focus is (mirrors the
  pattern from the working modifier-click demo)
- cursor: copy replaces crosshair (matches copy-affordance semantics)
- figure, h2–h4 and [data-widget-name] elements get a dashed indigo
  outline + subtle background tint when shift is held, so the user
  can see which elements are annotatable before clicking

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-18 00:18:56 +01:00
parent 46f4b0c25d
commit 4d0941b524

View File

@@ -140,9 +140,21 @@ function _ensureStyles() {
@keyframes _im-tin { from { opacity:0; transform:translateX(-50%) translateY(6px) } to { opacity:1; transform:translateX(-50%) translateY(0) } }
@keyframes _im-tout { from { opacity:1 } to { opacity:0 } }
/* ── Shift-held cursor override (applied to <body>) ─────────────────────── */
.impr-shift-mode,
.impr-shift-mode * { cursor: crosshair !important; }
/* ── Shift-held mode: cursor + element highlighting ─────────────────────── */
.impr-mode-shift,
.impr-mode-shift * { cursor: copy !important; }
/* Highlight "widget" elements so the user sees what can be annotated */
.impr-mode-shift #observablehq-main figure,
.impr-mode-shift #observablehq-main h2,
.impr-mode-shift #observablehq-main h3,
.impr-mode-shift #observablehq-main h4,
.impr-mode-shift #observablehq-main [data-widget-name] {
outline: 1px dashed rgba(99, 102, 241, 0.45);
background: rgba(99, 102, 241, 0.055) !important;
border-radius: 4px;
transition: background 0.1s, outline 0.1s;
}
`;
document.head.append(s);
}
@@ -197,7 +209,7 @@ function _toast(msg) {
let _initialized = false;
/**
* Wire right-click → improvement modal on the current page.
* Wire Shift+click → improvement modal on the current page.
* Safe to call multiple times — only the first call takes effect.
*
* @param {object} opts
@@ -209,15 +221,20 @@ export function initImprovementModal({ apiBase = "http://127.0.0.1:8000", domain
_initialized = true;
_ensureStyles();
// Shift-held cursor indicator
document.addEventListener("keydown", (e) => {
if (e.key === "Shift") document.body.classList.add("impr-shift-mode");
});
document.addEventListener("keyup", (e) => {
if (e.key === "Shift") document.body.classList.remove("impr-shift-mode");
});
// Remove shift-mode if window loses focus while Shift is held
window.addEventListener("blur", () => document.body.classList.remove("impr-shift-mode"));
// Track modifier state via keydown, keyup, AND mousemove so mode
// stays in sync even when focus changes between elements.
function _updateMode(e) {
if (e.shiftKey) {
document.body.classList.add("impr-mode-shift");
} else {
document.body.classList.remove("impr-mode-shift");
}
}
window.addEventListener("keydown", _updateMode);
window.addEventListener("keyup", _updateMode);
window.addEventListener("mousemove", _updateMode);
// Clear on blur in case Shift is held when the window loses focus
window.addEventListener("blur", () => document.body.classList.remove("impr-mode-shift"));
document.addEventListener("click", (e) => {
if (!e.shiftKey) return;