diff --git a/frontend/src/components/MessageList.css b/frontend/src/components/MessageList.css index ccb9594..a673d5d 100644 --- a/frontend/src/components/MessageList.css +++ b/frontend/src/components/MessageList.css @@ -4,98 +4,97 @@ padding: var(--sp-4); display: flex; flex-direction: column; - gap: 14px; } .message-row { + position: relative; display: flex; gap: var(--sp-2); - justify-content: flex-start; - align-items: flex-end; + padding: 1px var(--sp-2); + border-radius: 6px; } -.message-row-mine { - justify-content: flex-end; +.message-row-start { + margin-top: 10px; +} + +.message-row:hover { + background: var(--ds-surface); } .message-avatar-slot { - width: 28px; + width: 36px; flex: none; } -.message-bubble-wrap { - display: flex; - flex-direction: column; - align-items: flex-start; - max-width: 65%; +.message-content { + flex: 1; + min-width: 0; } -.message-row-mine .message-bubble-wrap { - align-items: flex-end; +.message-header { + display: flex; + align-items: baseline; + gap: 8px; + margin-bottom: 2px; } .message-author { - font-size: 0.76rem; - color: var(--ds-muted); - margin-bottom: 3px; - font-weight: 600; + font-size: 0.86rem; + font-weight: 700; + color: var(--ds-text); } -.message-bubble { - position: relative; - background: var(--ds-surface-2); - color: var(--ds-text); - padding: 8px 12px; - border-radius: 10px; +.message-time { + font-size: 0.68rem; + color: var(--ds-muted); + font-family: var(--mono); +} + +.message-text { font-size: 0.88rem; line-height: 1.45; + color: var(--ds-text); white-space: pre-wrap; word-break: break-word; } -.message-bubble-mine { - background: var(--ds-accent-2); +.message-edited { + font-style: italic; + color: var(--ds-muted); + font-size: 0.78rem; } .message-edit-link { display: none; position: absolute; - top: -18px; - right: 0; - background: transparent; - border: none; + top: 2px; + right: var(--sp-2); + background: var(--ds-surface-2); + border: 1px solid var(--ds-border); color: var(--ds-muted); font-size: 0.68rem; cursor: pointer; - padding: 2px 4px; + padding: 2px 8px; + border-radius: 6px; } .message-edit-link:hover { color: var(--ds-text); + border-color: var(--ds-accent); } -.message-bubble:hover .message-edit-link { +.message-row:hover .message-edit-link { display: inline; } .message-edit-input { background: var(--ds-surface-2); border: 1px solid var(--ds-accent); - border-radius: 10px; - padding: 8px 12px; + border-radius: 6px; + padding: 6px 10px; font-size: 0.88rem; color: var(--ds-text); font-family: var(--sans); width: 100%; } - -.message-time { - font-size: 0.68rem; - color: var(--ds-muted); - margin-top: 3px; - font-family: var(--mono); -} - -.message-edited { - font-style: italic; -} diff --git a/frontend/src/components/MessageList.tsx b/frontend/src/components/MessageList.tsx index 48264f8..a6088f0 100644 --- a/frontend/src/components/MessageList.tsx +++ b/frontend/src/components/MessageList.tsx @@ -37,21 +37,29 @@ export function MessageList({ messages, members, onEdit }: MessageListProps) { {messages.map((msg, i) => { const mine = msg.user_id === user?.id const prev = messages[i - 1] - const showAvatar = !mine && (!prev || prev.user_id !== msg.user_id) - const showName = showAvatar + // Mattermost-style grouping: every message shows who sent it, but + // consecutive messages from the same sender only repeat the + // avatar/name/timestamp header on the first one in the run -- + // applies uniformly, including to your own messages. + const isGroupStart = !prev || prev.user_id !== msg.user_id const editing = editingId === msg.id return ( -
- {!mine && ( -
- {showAvatar && ( - - )} -
- )} -
- {showName &&
{msg.username}
} +
+
+ {isGroupStart && ( + + )} +
+
+ {isGroupStart && ( +
+ {msg.username} + + {new Date(msg.created_at).toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })} + +
+ )} {editing ? ( commitEdit(msg.id)} /> ) : ( -
+
{msg.content} - {mine && ( - - )} + {msg.edited_at && (edited)}
)} -
- {new Date(msg.created_at).toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })} - {msg.edited_at && (edited)} -
+ {mine && !editing && ( + + )}
) })}