fix(reader): highlight color picker + window-aware note popover under CSP build
- Highlight color dots carried a nested-ternary + comma-sequence expression that the CSP-safe Alpine evaluator cannot parse — the buttons were dead. Logic moved to pickHighlightColor(color): sets the color, saves changes for edit-mode, creates the highlight for create-mode. - The selection popover (and its note area) rendered above the selection anchor with a fixed size, so on small windows or top-of-page selections it escaped the viewport. Placement is now window-aware: show-time clamping via estimated popover size, and a measure-and-shift pass when the note area widens the popover (the post-open adjustment runs well after the enter transition; mutating during it is what breaks compositor hit-testing).
This commit is contained in:
1 parent
3b66b981be
commit
6a598786e9
3 files changed
+50
-19
No files matched your search
@@ -1300,17 +1300,54 @@ document.addEventListener("alpine:init", () => {
|
||||
p.noteOpen = !!p.note && opts.mode === "edit";
|
||||
p.pdfPage = opts.pdfPage ?? -1;
|
||||
p.pdfRects = opts.pdfRects ?? [];
|
||||
// Clamp so the popover stays on screen (it anchors bottom-center;
|
||||
// the popover is ~240px wide, so the fixed margins must cover half
|
||||
// of it). NOTE: do not mutate the position after opening — touching
|
||||
// the style mid-enter-transition leaves the popover invisible to
|
||||
// compositor hit-testing (taps fall through to the content iframe).
|
||||
// Clamp so the popover stays on screen (it anchors bottom-center and
|
||||
// renders ABOVE the anchor: top = y - 10 - height). The size is
|
||||
// estimated up front — the note area is already open when editing an
|
||||
// existing note — and the position MUST be final before p.open = true
|
||||
// (mutating mid-enter-transition breaks compositor hit-testing).
|
||||
const w = window.innerWidth;
|
||||
const h = window.innerHeight;
|
||||
p.x = Math.min(Math.max(opts.x, 130), w - 130);
|
||||
p.y = Math.min(Math.max(opts.y, 60), h - 60);
|
||||
const estW = 240;
|
||||
const estH = p.noteOpen ? 300 : 130;
|
||||
p.x = Math.min(Math.max(opts.x, estW / 2 + 8), w - estW / 2 - 8);
|
||||
p.y = Math.min(Math.max(opts.y, estH + 18), h - 60);
|
||||
p.open = true;
|
||||
},
|
||||
// Note area opens after the popover is visible; the textarea widens the
|
||||
// popover, so measure the real box after render and shift it back inside
|
||||
// the window (the popover's own enter transition has finished by the
|
||||
// time a user clicks Note, so adjusting here is safe).
|
||||
openSelectionNote() {
|
||||
const p = this.selectionPopover;
|
||||
p.noteOpen = true;
|
||||
const w = window.innerWidth;
|
||||
const h = window.innerHeight;
|
||||
p.x = Math.min(Math.max(p.x, 148), w - 148);
|
||||
p.y = Math.min(Math.max(p.y, 318), h - 60);
|
||||
this.$nextTick(() => {
|
||||
const el = document.querySelector(".reader-popover") as HTMLElement | null;
|
||||
if (!el) return;
|
||||
const r = el.getBoundingClientRect();
|
||||
if (r.x < 8) p.x += 8 - r.x;
|
||||
if (r.right > w - 8) p.x -= r.right - (w - 8);
|
||||
if (r.y < 8) p.y += 8 - r.y;
|
||||
if (r.bottom > h - 8) p.y -= r.bottom - (h - 8);
|
||||
});
|
||||
},
|
||||
// Highlight color picker (CSP-safe: single method call — the previous
|
||||
// inline nested-ternary + comma-sequence expression is unparseable by
|
||||
// the CSP build's evaluator).
|
||||
pickHighlightColor(c: string) {
|
||||
const p = this.selectionPopover;
|
||||
p.color = c;
|
||||
if (p.noteOpen) {
|
||||
if (p.mode !== "create") this.saveHighlightChanges(true);
|
||||
} else if (p.mode === "create") {
|
||||
this.createHighlight(c);
|
||||
} else {
|
||||
this.saveHighlightChanges();
|
||||
}
|
||||
},
|
||||
hideSelectionPopover() {
|
||||
this.selectionPopover.open = false;
|
||||
this.selectionPopover.noteOpen = false;
|
||||
|
||||
Reference in new issue
Block a user