feat(messaging-ui): message timestamps + group/channel settings panel (0.1.5)

- Every message now shows a Slack-style time (clock today, then 'Yesterday',
  weekday, else a date; full timestamp on hover).
- New ConversationSettings panel for groups AND channels (public + private):
  rename, member list, add people (from the directory), remove, and leave.
  Opened from a new thread header gear; DMs show no gear. Adapter gains
  addMember/removeMember/renameConversation (optional, OPA still gates writes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 12:54:47 +05:30
parent aa73dee05d
commit 416cf59dc2
9 changed files with 350 additions and 3 deletions
@@ -8,6 +8,20 @@ const REACTION_EMOJIS = ['👍', '❤️', '😂', '🎉', '👀'];
const isImage = (mime: string): boolean => mime.startsWith('image/');
/** Slack-style message time: today shows the clock, then "Yesterday", weekday, else a date. */
function messageTime(iso: string): string {
const d = new Date(iso);
if (Number.isNaN(+d)) return '';
const now = new Date();
const time = d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
if (d.toDateString() === now.toDateString()) return time;
const yesterday = new Date(now);
yesterday.setDate(now.getDate() - 1);
if (d.toDateString() === yesterday.toDateString()) return `Yesterday ${time}`;
if (now.getTime() - d.getTime() < 7 * 86400000) return `${d.toLocaleDateString([], { weekday: 'short' })} ${time}`;
return `${d.toLocaleDateString([], { month: 'short', day: 'numeric' })} ${time}`;
}
function AttachmentView({ att }: { att: Attachment }) {
if (isImage(att.mime)) {
return (
@@ -54,6 +68,9 @@ export function MessageItem({
{m.text ? highlightMentions(m.text, memberNames) : null}
{m.attachment ? <AttachmentView att={m.attachment} /> : null}
</div>
<time className="miu-msg-time" dateTime={m.at} title={Number.isNaN(+new Date(m.at)) ? '' : new Date(m.at).toLocaleString()}>
{messageTime(m.at)}
</time>
<div className="miu-msg-actions">
{canReact ? (
<div className="miu-react-wrap">