0c8eaaf74b
Two bugs from the formatting work, both visible in the CRM messenger: 1. Inline code / code blocks were invisible in your OWN bubbles. `.miu-code` sets background: --miu-panel-2 (#1d1d26) while the is-mine override set only the colour to --miu-accent-text (#1a1206) — near-black on near-black, ~1.03:1 contrast. The chip now tints the accent bubble (rgba(0,0,0,.16)) instead of using the panel colour, so it reads against any accent. 2. The conversation list showed the raw last message, so a strikethrough message previewed as "~crazy~". Adds stripMarkup() — markers off, code unwrapped, nesting handled, honouring the same word-boundary rule so snake_case_name and "5 * 3" survive — and uses it for the preview line. Bumped to 0.1.10. SDK suite: 17 files / 98 tests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
54 lines
1.8 KiB
TypeScript
54 lines
1.8 KiB
TypeScript
import type { Conversation } from '../types';
|
|
import { stripMarkup } from '../rich-text';
|
|
|
|
/** Initials for the avatar chip — first letters of the first two words. */
|
|
function initials(title: string): string {
|
|
const parts = title.trim().split(/\s+/).filter(Boolean);
|
|
const chars = (parts[0]?.[0] ?? '') + (parts[1]?.[0] ?? '');
|
|
return (chars || '?').toUpperCase();
|
|
}
|
|
|
|
/**
|
|
* Presentational conversation list. Owns no data fetching — the parent passes the
|
|
* conversations (from useConversations) so a host can also drive it from its own store.
|
|
*/
|
|
export function ConversationList({
|
|
conversations,
|
|
selectedId,
|
|
onSelect,
|
|
}: {
|
|
conversations: Conversation[];
|
|
selectedId?: string | null;
|
|
onSelect: (threadId: string) => void;
|
|
}) {
|
|
if (conversations.length === 0) {
|
|
return <div className="miu-empty">No conversations yet.</div>;
|
|
}
|
|
return (
|
|
<ul className="miu-convlist" role="list">
|
|
{conversations.map((c) => (
|
|
<li key={c.threadId}>
|
|
<button
|
|
type="button"
|
|
className={`miu-convrow${c.threadId === selectedId ? ' is-active' : ''}`}
|
|
onClick={() => onSelect(c.threadId)}
|
|
>
|
|
<span className="miu-avatar" aria-hidden="true">
|
|
{c.membership === 'channel' ? '#' : initials(c.title)}
|
|
</span>
|
|
<span className="miu-convrow-main">
|
|
<span className="miu-convrow-title">{c.title}</span>
|
|
{c.lastMessage ? <span className="miu-convrow-preview">{stripMarkup(c.lastMessage)}</span> : null}
|
|
</span>
|
|
{c.unread > 0 ? (
|
|
<span className="miu-badge" aria-label={`${c.unread} unread`}>
|
|
{c.unread}
|
|
</span>
|
|
) : null}
|
|
</button>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
);
|
|
}
|