From c99cbb3e1483a832cfd809762b6f195d73628094 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sun, 23 Aug 2026 01:00:39 -0400 Subject: [PATCH] cards: clamp the web note preview, as Android always has MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M13 step 4 asked for no bold first line, and step 3 already delivered that — removing `note.title` took the card's

and the Android editor's bold field with it. What step 4 also asked for, and hadn't been done, was the other half: "be willing to spend something small on legibility that isn't weight on the first line." The web card rendered the entire body. Android has always clamped to eight lines (`MAX_PREVIEW_LINES`), so one long note produced a card taller than the screen on the web and pushed the rest of the board off it — a real asymmetry between two surfaces that are supposed to be peers. It matters more without a title. The first line used to be what your eye caught; with one weight throughout, an unbounded card is just a wall, and the note beside it is the one you were actually looking for. Clamped in the STRING, not with CSS `line-clamp` — that needs a `-webkit-box` and behaves unreliably around the block elements MarkdownText emits (lists, quotes, fenced code). Doing it before the parse is deterministic, matches Android's semantics exactly, and skips parsing a body the card was never going to show. --- frontend/src/components/NoteCard.vue | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/NoteCard.vue b/frontend/src/components/NoteCard.vue index 97be5fb..04783c9 100644 --- a/frontend/src/components/NoteCard.vue +++ b/frontend/src/components/NoteCard.vue @@ -54,6 +54,26 @@ const trashUrgent = computed(() => trashDays.value !== null && trashDays.value < const firstImage = computed(() => props.note.attachments.find((a) => a.mime.startsWith("image/"))); const otherAttachments = computed(() => props.note.attachments.filter((a) => !a.mime.startsWith("image/"))); +// How much of a note the CARD shows. Android has always clamped to 8 +// (`MAX_PREVIEW_LINES`); the web rendered the whole body, so one long note could +// produce a card taller than the screen and push everything else off the board. +// +// It matters more now that the title is gone (M13 step 4). The first line used to be +// the thing your eye caught; with one weight throughout, an unbounded card is just a +// wall, and the note next to it is the one you were looking for. +// +// Clamped in the STRING rather than with CSS `line-clamp`, which needs a +// `-webkit-box` and behaves unreliably around the block elements MarkdownText emits +// (lists, quotes, fenced code). This is deterministic, matches Android's semantics +// exactly, and skips parsing a body the card was never going to show. +const PREVIEW_LINES = 8; + +const bodyPreview = computed(() => { + const lines = props.note.body.split("\n"); + if (lines.length <= PREVIEW_LINES) return props.note.body; + return lines.slice(0, PREVIEW_LINES).join("\n") + "\n…"; +}); + const root = ref(null); // --- Drag-to-reorder. Pointer Events, gated behind an explicit grip handle so a @@ -222,7 +242,7 @@ onBeforeUnmount(() => document.removeEventListener("mousedown", onDocMousedown)) @keydown.enter="emit('open', note)" >
- +