Compare commits
2 commits
2d415d88a3
...
4ab0d95cad
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ab0d95cad | |||
| 4cc2f1ae74 |
1 changed files with 29 additions and 51 deletions
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { onMount, untrack } from 'svelte';
|
||||
import CirclePlusIcon from '@lucide/svelte/icons/circle-plus';
|
||||
import DownloadIcon from '@lucide/svelte/icons/download';
|
||||
import EllipsisIcon from '@lucide/svelte/icons/ellipsis';
|
||||
import ArrowUpIcon from '@lucide/svelte/icons/arrow-up';
|
||||
|
|
@ -117,15 +118,18 @@
|
|||
return rectBeside(a, slot.dir, s);
|
||||
}
|
||||
|
||||
/** Hit area of the add-page bar: a strip hugging the anchor's free edge. */
|
||||
function barRect(slot: Slot): Rect | null {
|
||||
/** The add-page button: a 24 px circle centred on the anchor's free edge, 6 px out. */
|
||||
function plusRect(slot: Slot): Rect | null {
|
||||
const a = doc.rectOf(slot.anchor);
|
||||
if (!a) return null;
|
||||
const t = 20 / viewport.scale;
|
||||
if (slot.dir === 'right') return { x: a.x + a.width, y: a.y, width: t, height: a.height };
|
||||
if (slot.dir === 'left') return { x: a.x - t, y: a.y, width: t, height: a.height };
|
||||
if (slot.dir === 'down') return { x: a.x, y: a.y + a.height, width: a.width, height: t };
|
||||
return { x: a.x, y: a.y - t, width: a.width, height: t };
|
||||
const d = 24 / viewport.scale;
|
||||
const gap = 6 / viewport.scale;
|
||||
const cx = a.x + (a.width - 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 === 'left') return { x: a.x - gap - d, y: cy, width: d, height: d };
|
||||
if (slot.dir === 'down') return { x: cx, y: a.y + a.height + gap, width: d, height: d };
|
||||
return { x: cx, y: a.y - gap - d, width: d, height: d };
|
||||
}
|
||||
|
||||
/** Run a tree change without the anchor page jumping on screen. */
|
||||
|
|
@ -291,10 +295,10 @@
|
|||
|
||||
// Fingers ink only when enabled and no pen has been used; otherwise they pan/zoom.
|
||||
const fingerInks = tools.inking && settings.data.fingerDraw && !palm.penSeen;
|
||||
// Taps on an add-page bar get the same palm policy as writing.
|
||||
const bar = target.closest<HTMLElement>('.ghost');
|
||||
// Taps on an add-page button get the same palm policy as writing.
|
||||
const plus = target.closest<HTMLElement>('.ghost');
|
||||
if (e.pointerType === 'touch') {
|
||||
const decision = palm.evaluate(e, fingerInks || bar ? 'draw' : 'navigate');
|
||||
const decision = palm.evaluate(e, fingerInks || plus ? 'draw' : 'navigate');
|
||||
if (!decision.accept) return; // palm: ignore entirely
|
||||
touches.set(e.pointerId, p);
|
||||
if (touches.size >= 2) {
|
||||
|
|
@ -305,9 +309,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (bar && e.button === 0) {
|
||||
if (plus && e.button === 0) {
|
||||
e.preventDefault();
|
||||
const slot = { anchor: bar.dataset.anchor!, dir: bar.dataset.dir as Dir };
|
||||
const slot = { anchor: plus.dataset.anchor!, dir: plus.dataset.dir as Dir };
|
||||
gesture = { kind: 'add', pointerId: e.pointerId, pointerType: e.pointerType, startX: p.x, startY: p.y, slot };
|
||||
capture(e.pointerId);
|
||||
return;
|
||||
|
|
@ -397,7 +401,7 @@
|
|||
}
|
||||
|
||||
if (gesture.kind === 'add') {
|
||||
// Dragging off the bar is not a tap.
|
||||
// Dragging off the button is not a tap.
|
||||
if (Math.hypot(p.x - gesture.startX, p.y - gesture.startY) > 12) gesture = null;
|
||||
return;
|
||||
}
|
||||
|
|
@ -593,7 +597,7 @@
|
|||
{/each}
|
||||
|
||||
{#each ghostSlots as slot (slot.anchor + slot.dir)}
|
||||
{@const r = barRect(slot)}
|
||||
{@const r = plusRect(slot)}
|
||||
{#if r}
|
||||
<!-- Pointer taps go through the palm-checked gesture; onclick only serves the keyboard. -->
|
||||
<button
|
||||
|
|
@ -603,7 +607,9 @@
|
|||
style="left:{r.x}px; top:{r.y}px; width:{r.width}px; height:{r.height}px"
|
||||
title="Add page ({slot.dir})"
|
||||
onclick={(e) => e.detail === 0 && addPage(slot.anchor, slot.dir)}
|
||||
></button>
|
||||
>
|
||||
<CirclePlusIcon size="100%" strokeWidth={1.5} />
|
||||
</button>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
|
|
@ -726,46 +732,18 @@
|
|||
}
|
||||
.ghost {
|
||||
position: absolute;
|
||||
background: none;
|
||||
display: grid;
|
||||
background: var(--bg-canvas);
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
color: var(--faint);
|
||||
cursor: pointer;
|
||||
transition: color 0.12s;
|
||||
}
|
||||
/* The visible bar: 4 screen px thick, 6 px off the page edge. */
|
||||
.ghost::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background: var(--ghost-border);
|
||||
border-radius: calc(2px / var(--s));
|
||||
transition: background 0.12s;
|
||||
}
|
||||
.ghost[data-dir='left']::before,
|
||||
.ghost[data-dir='right']::before {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: calc(4px / var(--s));
|
||||
}
|
||||
.ghost[data-dir='up']::before,
|
||||
.ghost[data-dir='down']::before {
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: calc(4px / var(--s));
|
||||
}
|
||||
.ghost[data-dir='right']::before {
|
||||
left: calc(6px / var(--s));
|
||||
}
|
||||
.ghost[data-dir='left']::before {
|
||||
right: calc(6px / var(--s));
|
||||
}
|
||||
.ghost[data-dir='down']::before {
|
||||
top: calc(6px / var(--s));
|
||||
}
|
||||
.ghost[data-dir='up']::before {
|
||||
bottom: calc(6px / var(--s));
|
||||
}
|
||||
.ghost:hover::before,
|
||||
.ghost:focus-visible::before {
|
||||
background: var(--accent);
|
||||
.ghost:hover,
|
||||
.ghost:focus-visible {
|
||||
color: var(--accent);
|
||||
}
|
||||
.slot {
|
||||
position: absolute;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue