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

+27 -7
View File
@@ -61,11 +61,11 @@ templ AnnotationsBanner(book handlers.MediaDetail) {
<div class="space-y-2">
<template x-for="row in bannerRows" :key="row.key">
<div class="card p-0 overflow-hidden relative">
<!-- Note-attached indicator: quiet stroke glyph in the
card's upper-right corner (never left of text) —
highlights with an attached note only. -->
<!-- Note indicator: a quiet stroke glyph in the card's
upper-right corner (never left of text) — every
note row, and highlights with an attached note. -->
<svg
x-show="row.kind === 'highlight' && row.hasNote"
x-show="row.kind === 'note' || (row.kind === 'highlight' && row.hasNote)"
class="absolute top-2 right-2 pointer-events-none reader-icon"
style="color: var(--text-secondary);"
width="13" height="13" viewBox="0 0 20 20" aria-hidden="true"
@@ -73,7 +73,7 @@ templ AnnotationsBanner(book handlers.MediaDetail) {
<button
type="button"
class="w-full text-left px-4 py-3 flex items-start gap-3 hover:bg-surface-hover"
:class="row.kind === 'highlight' && row.hasNote ? 'pr-8' : ''"
:class="(row.kind === 'note' || (row.kind === 'highlight' && row.hasNote)) ? 'pr-8' : ''"
@click="row.expanded = !row.expanded"
>
<span
@@ -115,8 +115,28 @@ templ AnnotationsBanner(book handlers.MediaDetail) {
>✕ Delete</button>
</div>
</div>
<!-- Expanded rich body (markdown pipeline) -->
<div x-show="row.expanded" class="note-rich px-4 pb-4" x-html="row.rich"></div>
<!-- Expanded rich body (markdown pipeline). Highlight
rows split at the highlight→note boundary: the
selection (bordered in the row color), then a
labeled divider, then the note markdown. -->
<div x-show="row.expanded" class="px-4 pb-4">
<p
x-show="row.kind === 'highlight'"
class="text-sm"
:style="row.kind === 'highlight' ? 'border-left: 3px solid ' + row.color + '; padding-left: .75rem; color: var(--text-secondary); margin: 0 0 ' + (row.hasNote ? '.75rem' : '0') + ';' : 'color: var(--text-secondary);'"
x-text="row.richSelection"
></p>
<template x-if="row.kind === 'highlight' && row.hasNote">
<div
class="flex items-center gap-1 pt-2 pb-1 mt-2 border-t"
style="border-color: var(--border); color: var(--text-secondary);"
>
<svg class="reader-icon" width="12" height="12" viewBox="0 0 20 20" aria-hidden="true"><path d="M 4 13 L 4 16 L 7 16 L 14.5 8.5 L 11.5 5.5 L 4 13 M 12.5 4.5 L 15.5 7.5"></path></svg>
<span class="text-xs font-medium uppercase tracking-wide">Note</span>
</div>
</template>
<div class="note-rich text-sm" x-html="row.richNote"></div>
</div>
</div>
</template>
</div>