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 8febe9d4..19fef94a 100644 --- a/artifacts/tx-os/src/components/notes/incoming-note-popup.tsx +++ b/artifacts/tx-os/src/components/notes/incoming-note-popup.tsx @@ -12,6 +12,7 @@ import { Reply, Check, ExternalLink, X, GripVertical } from "lucide-react"; import { Button } from "@/components/ui/button"; import { colorBg, + colorAccent, useMarkNoteRead, useToggleChecklistItem, userDisplayName, @@ -113,10 +114,15 @@ function clampToViewport(pos: StoredPos): StoredPos { function PopupChecklistPreview({ items, noteId, + noteColor, }: { items: ChecklistItem[]; noteId: number; + // Match the checked-checkbox accent to the parent note's color so the + // checkbox tint belongs to the card (pink note → pink check, etc.). + noteColor?: string | null; }) { + const accent = colorAccent(noteColor); const toggle = useToggleChecklistItem(); // The server intentionally does NOT echo `note_checklist_changed` // back to the actor, so the popup's queued snapshot would stay stale @@ -205,7 +211,7 @@ function PopupChecklistPreview({ }, ); }} - className="mt-0.5 h-4 w-4 rounded border-black/30 accent-amber-500" + className={`mt-0.5 h-4 w-4 rounded border-black/30 ${accent}`} data-testid={`incoming-note-popup-checklist-check-${it.id}`} /> ) : ( bodyContent && ( diff --git a/artifacts/tx-os/src/lib/notes-api.ts b/artifacts/tx-os/src/lib/notes-api.ts index 475d2ae4..6caf5ac4 100644 --- a/artifacts/tx-os/src/lib/notes-api.ts +++ b/artifacts/tx-os/src/lib/notes-api.ts @@ -530,23 +530,40 @@ export function useDeleteLabel() { }); } -export const NOTE_COLORS: { id: string; bg: string; ring: string }[] = [ - { id: "default", bg: "bg-white dark:bg-card", ring: "ring-slate-300" }, - { id: "red", bg: "bg-red-100 dark:bg-red-900/40", ring: "ring-red-400" }, - { id: "orange", bg: "bg-orange-100 dark:bg-orange-900/40", ring: "ring-orange-400" }, - { id: "yellow", bg: "bg-yellow-100 dark:bg-yellow-900/40", ring: "ring-yellow-400" }, - { id: "green", bg: "bg-green-100 dark:bg-green-900/40", ring: "ring-green-400" }, - { id: "teal", bg: "bg-teal-100 dark:bg-teal-900/40", ring: "ring-teal-400" }, - { id: "blue", bg: "bg-sky-100 dark:bg-sky-900/40", ring: "ring-sky-400" }, - { id: "purple", bg: "bg-purple-100 dark:bg-purple-900/40", ring: "ring-purple-400" }, - { id: "pink", bg: "bg-pink-100 dark:bg-pink-900/40", ring: "ring-pink-400" }, - { id: "gray", bg: "bg-slate-200 dark:bg-slate-800/60", ring: "ring-slate-400" }, +export const NOTE_COLORS: { + id: string; + bg: string; + ring: string; + accent: string; +}[] = [ + // Tailwind v4 scans these literal class strings at build time, so each + // accent-* utility below ends up in the generated CSS even though we + // pick the right one at runtime via colorAccent(). For the "default" + // (white/card) note we keep amber so the checked box stays visible + // against a neutral surface in both light and dark mode; every other + // color points at its own family's *-500 accent so the checked tint + // belongs to the card instead of clashing with it. + { id: "default", bg: "bg-white dark:bg-card", ring: "ring-slate-300", accent: "accent-amber-500" }, + { id: "red", bg: "bg-red-100 dark:bg-red-900/40", ring: "ring-red-400", accent: "accent-red-500" }, + { id: "orange", bg: "bg-orange-100 dark:bg-orange-900/40", ring: "ring-orange-400", accent: "accent-orange-500" }, + { id: "yellow", bg: "bg-yellow-100 dark:bg-yellow-900/40", ring: "ring-yellow-400", accent: "accent-yellow-500" }, + { id: "green", bg: "bg-green-100 dark:bg-green-900/40", ring: "ring-green-400", accent: "accent-green-500" }, + { id: "teal", bg: "bg-teal-100 dark:bg-teal-900/40", ring: "ring-teal-400", accent: "accent-teal-500" }, + { id: "blue", bg: "bg-sky-100 dark:bg-sky-900/40", ring: "ring-sky-400", accent: "accent-sky-500" }, + { id: "purple", bg: "bg-purple-100 dark:bg-purple-900/40", ring: "ring-purple-400", accent: "accent-purple-500" }, + { id: "pink", bg: "bg-pink-100 dark:bg-pink-900/40", ring: "ring-pink-400", accent: "accent-pink-500" }, + { id: "gray", bg: "bg-slate-200 dark:bg-slate-800/60", ring: "ring-slate-400", accent: "accent-slate-500" }, ]; export function colorBg(id: string): string { return NOTE_COLORS.find((c) => c.id === id)?.bg ?? NOTE_COLORS[0].bg; } +export function colorAccent(id: string | null | undefined): string { + if (!id) return NOTE_COLORS[0].accent; + return NOTE_COLORS.find((c) => c.id === id)?.accent ?? NOTE_COLORS[0].accent; +} + export function userDisplayName( u: UserSummary | null | undefined, lang: string, diff --git a/artifacts/tx-os/src/pages/notes.tsx b/artifacts/tx-os/src/pages/notes.tsx index ddcef8bf..497a0221 100644 --- a/artifacts/tx-os/src/pages/notes.tsx +++ b/artifacts/tx-os/src/pages/notes.tsx @@ -74,6 +74,7 @@ import { type UserSummary, NOTE_COLORS, colorBg, + colorAccent, useArchiveReceivedNote, useCreateLabel, useCreateNote, @@ -773,6 +774,7 @@ function NoteCard({ items={note.items ?? []} testIdPrefix={`note-card-checklist-${note.id}`} className="mt-1" + noteColor={note.color} onToggle={(itemId, done) => { const next = (note.items ?? []).map((it) => it.id === itemId ? { ...it, done } : it, @@ -1448,6 +1450,7 @@ function ReceivedList({ items={n.items ?? []} testIdPrefix={`received-note-checklist-${n.id}`} className="mt-1" + noteColor={n.color} /> ) : ( n.content && ( @@ -1507,6 +1510,7 @@ function SentList({ items={n.items ?? []} testIdPrefix={`sent-note-checklist-${n.id}`} className="mt-1" + noteColor={n.color} /> ) : ( n.content && ( @@ -1884,6 +1888,7 @@ function ThreadDialog({ void; testIdPrefix: string; className?: string; + // Optional: when provided, the checked-checkbox accent matches the + // parent note's color (pink note → pink check, etc.). Falls back to + // amber when omitted or unknown — see colorAccent(). + noteColor?: string | null; }) { if (items.length === 0) return null; + const accent = colorAccent(noteColor); return (
onToggle?.(it.id, e.target.checked)} - className="mt-0.5 h-4 w-4 rounded border-black/30 accent-amber-500 disabled:cursor-default" + className={`mt-0.5 h-4 w-4 rounded border-black/30 ${accent} disabled:cursor-default`} data-testid={`${testIdPrefix}-check-${it.id}`} />