Enlarge the add-page button and let fingers tap it

The button is now a 32 px circle in a 48 px hit area, 8 px off the
page edge. Touch taps on it were palm-checked with the 'draw' policy,
which rejects every finger for 5 s after pen activity and while the pen
hovers, so fingers rarely got through. Use the 'navigate' policy
instead: pen-down, palm-sized contacts and touches right after pen use
are still rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GaoZtJQZwLXkEgWs8twCia
This commit is contained in:
agent 2026-09-27 20:56:04 +00:00
parent 4cc2f1ae74
commit a813c1c086

View file

@ -118,18 +118,20 @@
return rectBeside(a, slot.dir, s); return rectBeside(a, slot.dir, s);
} }
/** The add-page button: a 24 px circle centred on the anchor's free edge, 6 px out. */ /**
* Hit area of the add-page button: 48 px square touching the middle of the anchor's
* free edge. The visible 32 px circle sits centred in it, 8 px off the page.
*/
function plusRect(slot: Slot): Rect | null { function plusRect(slot: Slot): Rect | null {
const a = doc.rectOf(slot.anchor); const a = doc.rectOf(slot.anchor);
if (!a) return null; if (!a) return null;
const d = 24 / viewport.scale; const d = 48 / viewport.scale;
const gap = 6 / viewport.scale;
const cx = a.x + (a.width - d) / 2; const cx = a.x + (a.width - d) / 2;
const cy = a.y + (a.height - d) / 2; const cy = a.y + (a.height - d) / 2;
if (slot.dir === 'right') return { x: a.x + a.width + gap, y: cy, width: d, height: d }; if (slot.dir === 'right') return { x: a.x + a.width, y: cy, width: d, height: d };
if (slot.dir === 'left') return { x: a.x - gap - d, y: cy, width: d, height: d }; if (slot.dir === 'left') return { x: a.x - d, y: cy, width: d, height: d };
if (slot.dir === 'down') return { x: cx, y: a.y + a.height + gap, width: d, height: d }; if (slot.dir === 'down') return { x: cx, y: a.y + a.height, width: d, height: d };
return { x: cx, y: a.y - gap - d, width: d, height: d }; return { x: cx, y: a.y - d, width: d, height: d };
} }
/** Run a tree change without the anchor page jumping on screen. */ /** Run a tree change without the anchor page jumping on screen. */
@ -295,10 +297,11 @@
// Fingers ink only when enabled and no pen has been used; otherwise they pan/zoom. // Fingers ink only when enabled and no pen has been used; otherwise they pan/zoom.
const fingerInks = tools.inking && settings.data.fingerDraw && !palm.penSeen; const fingerInks = tools.inking && settings.data.fingerDraw && !palm.penSeen;
// Taps on an add-page button get the same palm policy as writing. // Taps on an add-page button are palm-checked like navigation: still rejected for
// pen-down, palm-sized contacts and right after pen use, but not for the 5 s pen session.
const plus = target.closest<HTMLElement>('.ghost'); const plus = target.closest<HTMLElement>('.ghost');
if (e.pointerType === 'touch') { if (e.pointerType === 'touch') {
const decision = palm.evaluate(e, fingerInks || plus ? 'draw' : 'navigate'); const decision = palm.evaluate(e, fingerInks && !plus ? 'draw' : 'navigate');
if (!decision.accept) return; // palm: ignore entirely if (!decision.accept) return; // palm: ignore entirely
touches.set(e.pointerId, p); touches.set(e.pointerId, p);
if (touches.size >= 2) { if (touches.size >= 2) {
@ -395,7 +398,7 @@
// A touch stroke is cut off as soon as the palm policy rejects it // A touch stroke is cut off as soon as the palm policy rejects it
// (e.g. the pen just came into range). // (e.g. the pen just came into range).
if (gesture.pointerType === 'touch' && !palm.evaluate(e).accept) { if (gesture.pointerType === 'touch' && !palm.evaluate(e, gesture.kind === 'add' ? 'navigate' : 'draw').accept) {
cancelGesture(); cancelGesture();
return; return;
} }
@ -434,7 +437,7 @@
const g = gesture; const g = gesture;
gesture = null; gesture = null;
if (g.kind === 'add') { if (g.kind === 'add') {
if (e.type === 'pointerup' && (g.pointerType !== 'touch' || palm.evaluate(e).accept)) addPage(g.slot.anchor, g.slot.dir); if (e.type === 'pointerup' && (g.pointerType !== 'touch' || palm.evaluate(e, 'navigate').accept)) addPage(g.slot.anchor, g.slot.dir);
} else if (g.kind === 'draw') { } else if (g.kind === 'draw') {
live = null; live = null;
if (e.type === 'pointerup') doc.addStroke(g.pageId, g.rec.stroke); if (e.type === 'pointerup') doc.addStroke(g.pageId, g.rec.stroke);
@ -608,7 +611,7 @@
title="Add page ({slot.dir})" title="Add page ({slot.dir})"
onclick={(e) => e.detail === 0 && addPage(slot.anchor, slot.dir)} onclick={(e) => e.detail === 0 && addPage(slot.anchor, slot.dir)}
> >
<CirclePlusIcon size="100%" strokeWidth={1.5} /> <span class="plus"><CirclePlusIcon size="100%" strokeWidth={1.5} /></span>
</button> </button>
{/if} {/if}
{/each} {/each}
@ -733,9 +736,9 @@
.ghost { .ghost {
position: absolute; position: absolute;
display: grid; display: grid;
background: var(--bg-canvas); place-items: center;
background: none;
border: 0; border: 0;
border-radius: 50%;
padding: 0; padding: 0;
color: var(--faint); color: var(--faint);
cursor: pointer; cursor: pointer;
@ -745,6 +748,13 @@
.ghost:focus-visible { .ghost:focus-visible {
color: var(--accent); color: var(--accent);
} }
.ghost .plus {
display: grid;
width: calc(32px / var(--s));
height: calc(32px / var(--s));
border-radius: 50%;
background: var(--bg-canvas);
}
.slot { .slot {
position: absolute; position: absolute;
display: grid; display: grid;