Let a margin remark become a note, and lead to it ever after

Some remarks turn into a page of their own. "Notiz anlegen" on a margin card
makes one, titles it from what was written, and goes there; the pin keeps its id
so the passage leads to that note afterwards. The note is created with a link
back to the document, so the connection reads both ways and the document lists it
among its backlinks — a note born from a passage should not be a note with
nothing on it saying which passage. An existing note can be linked instead, and a
link can be let go of without touching the note. Both are offered on the phone
sheet too.

Two older bugs stood in the way and are fixed:

`openLinkTarget` finds a note's notebook by looking it up in the notes list, and
a note created in the same tick is not in the copy that callback closed over — so
jumping to a fresh note went nowhere at all. Creating one now navigates by the
notebook it already knows.

A drawing save waits 700ms for the next stroke, and leaving the document inside
that window dropped it. That is precisely what turning a remark into a note does,
so the link would have been lost on the way out. The viewer flushes a pending
write when it unmounts, which also covers drawing and navigating away quickly.

215 unit tests, 229 browser checks across eleven suites.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-08-10 16:40:38 +02:00
1 parent 011ba82a94
commit 502aecfc92
10 files changed
+541 -12

No files matched your search

+50 -1
View File
@@ -12,7 +12,7 @@ import { useEffect, useRef, useState } from "react";
* The page stays visible above it, so the passage the note is about is still
* there while writing about it.
*/
export function PdfNoteSheet({ T, note, number, onChange, onClose, onRemove }) {
export function PdfNoteSheet({ T, note, number, onChange, onClose, onRemove, link }) {
const [draft, setDraft] = useState(note.text);
const areaRef = useRef(null);
@@ -109,6 +109,55 @@ export function PdfNoteSheet({ T, note, number, onChange, onClose, onRemove }) {
}}
/>
{/* Same two ways out as the margin card: some remarks turn into a page of
their own, and the pin should lead there afterwards. */}
<div style={{ display: "flex", alignItems: "center", gap: 14, marginTop: 8 }}>
{note.noteId ? (
<button
data-pin-goto={note.noteId}
onClick={() => link.onOpenNote(note.noteId)}
style={{
display: "flex",
alignItems: "center",
gap: 5,
flex: 1,
minWidth: 0,
border: "none",
background: "transparent",
color: T.accent,
cursor: "pointer",
fontSize: 12,
fontWeight: 600,
padding: 0,
textAlign: "left",
}}
>
<span style={{ flexShrink: 0 }}>→</span>
<span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
{link.labelOf?.(note.noteId) ?? "Notiz gelöscht"}
</span>
</button>
) : (
<button
data-pin-make-note
onClick={() => {
commit();
link.onCreate(draft);
}}
style={{
border: "none",
background: "transparent",
color: T.accent,
cursor: "pointer",
fontSize: 12,
padding: 0,
}}
>
Notiz anlegen
</button>
)}
</div>
<button
onClick={close}
style={{