diff --git a/artifacts/tx-os/public/opengraph.jpg b/artifacts/tx-os/public/opengraph.jpg index eb304be9..c61a8cde 100644 Binary files a/artifacts/tx-os/public/opengraph.jpg and b/artifacts/tx-os/public/opengraph.jpg differ diff --git a/artifacts/tx-os/src/components/notes/incoming-note-popup.tsx b/artifacts/tx-os/src/components/notes/incoming-note-popup.tsx index f9b22f55..9ce29d4c 100644 --- a/artifacts/tx-os/src/components/notes/incoming-note-popup.tsx +++ b/artifacts/tx-os/src/components/notes/incoming-note-popup.tsx @@ -14,6 +14,7 @@ import { colorBg, useMarkNoteRead, userDisplayName, + type ChecklistItem, type UserSummary, } from "@/lib/notes-api"; import { @@ -96,6 +97,46 @@ function clampToViewport(pos: StoredPos): StoredPos { }; } +/** + * Read-only checklist render that mirrors the visual style of the + * NoteCard's `ChecklistView` (notes.tsx). Inlined here to keep the + * popup self-contained — the popup is purely a preview surface, so + * the checkboxes are not interactive (toggling is reserved for the + * full Notes page after "Open note"). + */ +function PopupChecklistPreview({ items }: { items: ChecklistItem[] }) { + if (!items || items.length === 0) return null; + return ( +
+ {items.map((it) => ( +
+ + + {it.text || "\u00A0"} + +
+ ))} +
+ ); +} + export function IncomingNotePopup() { const { t, i18n } = useTranslation(); const isRtl = i18n.language === "ar"; @@ -181,6 +222,10 @@ export function IncomingNotePopup() { const replyPayload = isReply ? (current as Extract) : null; + const notePayload = + current && current.kind !== "reply" + ? (current as Extract) + : null; const senderForHeader: UserSummary | null = useMemo(() => { if (!current) return null; @@ -288,6 +333,16 @@ export function IncomingNotePopup() { const bodyContent = replyPayload ? replyPayload.replyContent : current.content; + // Render the inner sticky-note as faithfully as the NoteCard does: + // text body for "text" notes, read-only checklist for "checklist". + // Reply-variant popups always render the reply text as plain content. + const isChecklistNote = + !!notePayload && + notePayload.noteKind === "checklist" && + Array.isArray(notePayload.items); + const checklistItems = isChecklistNote + ? (notePayload!.items as ChecklistItem[]) + : []; return ( // The popup is "floating", not modal: render the card directly as @@ -368,22 +423,31 @@ export function IncomingNotePopup() { - {/* Body */} + {/* Body — render the inner note as a real sticky note. The + outer floating frame (header + actions) keeps its chrome; + this inner block matches the NoteCard surface so users see + the same artefact they'd see on the Notes page. */}
-
- {bodyTitle} -
- {bodyContent && ( -
- {bodyContent} + {bodyTitle && ( +
+ {bodyTitle}
)} + {isChecklistNote ? ( + + ) : ( + bodyContent && ( +
+ {bodyContent} +
+ ) + )}
{queueLength > 1 && ( @@ -395,16 +459,19 @@ export function IncomingNotePopup() {
)} + {/* Action row — exactly three buttons: Done, Open note, + Reply. The standalone Dismiss button was removed; the + X in the header still closes. */}
- {!replyPayload && ( - - )}