fix(web): banner highlight-note dialog prefilled; explicit note boundary; pencil on every note row

- BUG: startBannerEdit extracted the note by splitting row.rich — the
  RENDERED HTML — on \n\n, which the concatenated markup never
  contains, so highlight-note dialogs always opened empty. Both row
  kinds carry the raw note on bannerSources; use that lookup.
- Expanded body now splits at the highlight→note boundary: the
  selection paragraph (left border in the row's highlight color), a
  divider + pencil NOTE label, then the note markdown — instead of the
  two texts flowing together.
- The note-indicator pencil (corner badge) now shows on ALL note rows,
  not just highlights with attached notes.

Verified in headless Chromium: badge on note and highlight rows;
expanded highlight shows the bordered selection, NOTE label, and note
markdown; the highlight edit dialog prefills with the note text.
This commit is contained in:
John O'Keefe committed 2026-10-08 09:11:47 -04:00
1 parent e7ccd7b222
commit 44c0e5640f
4 files changed
+49 -22

No files matched your search

+7 -6
View File
@@ -225,13 +225,14 @@ Alpine.data("bookDetail", () => {
},
// ----- note edit/delete at the banner (objective 8a) -----
startBannerEdit(row: AnnotationRow): void {
// Highlight rows edit the note ATTACHED to the highlight (never the
// highlight itself): rich = "<selection head>\n\n<note source>".
// Both kinds carry the raw note body on their source: highlights
// hold the ATTACHED note (never the highlight itself), location
// notes hold their content. The old code parsed row.rich (rendered
// HTML — no \n\n separators in it) and came up empty every time.
this.bannerEditRow = row;
this.bannerEditText =
row.kind === "highlight"
? String((row.rich.split("\n\n").slice(1).join("\n\n") || "")).trim()
: String(this.bannerSources.find(s => s.row.key === row.key)?.source ?? "");
this.bannerEditText = String(
this.bannerSources.find(s => s.row.key === row.key)?.source ?? "",
);
this.bannerEditOpen = true;
},
async saveBannerNote() {