diff --git a/apps/web/src/app.css b/apps/web/src/app.css index fd8d5180c..2aab04de8 100644 --- a/apps/web/src/app.css +++ b/apps/web/src/app.css @@ -3783,6 +3783,46 @@ tr.insights-row-clickable:hover { font-weight: var(--font-weight-medium); line-height: 1.55; } +.chat-thread-message[data-author="me"] { + justify-content: flex-end; +} +.chat-thread-message[data-author="me"] .chat-thread-body { + display: flex; + flex-direction: column; + align-items: flex-end; + max-width: min(76ch, 78%); +} +.chat-thread-own-bubble { + background: var(--surface-sunk); + box-shadow: inset 0 0 0 1px var(--border); + padding: 0.625rem 0.875rem; + border-radius: 1rem 1rem 0.25rem 1rem; + overflow-wrap: anywhere; +} +.chat-thread-head { + display: flex; + align-items: baseline; + gap: 0.5rem; + margin-bottom: 0.125rem; +} +.chat-thread-head b { + font-size: 0.875rem; + font-weight: 800; +} +.chat-thread-head time { + font-size: 0.75rem; + color: var(--muted-foreground); + font-variant-numeric: tabular-nums; +} +.chat-system-line { + margin: 0 0 0.5rem 2.75rem; + font-size: 0.8125rem; + line-height: 1.5; + color: var(--muted-foreground); +} +.chat-system-line b { + font-weight: 700; +} .chat-thread-error { margin: 0.5rem 0; font-size: 0.82rem; diff --git a/apps/web/src/chat/styles.css b/apps/web/src/chat/styles.css index a37227496..967e72126 100644 --- a/apps/web/src/chat/styles.css +++ b/apps/web/src/chat/styles.css @@ -1035,8 +1035,7 @@ /* The owner asked for own messages back on the right, evaluated per viewer (`isOwn` in timeline.tsx already keys off `currentUser`, never a fixed account) — reversing flat, no-alignment timeline. Still - no bubble, no border, no background fill: only the row mirrors, so the - avatar sits on the right and the header/text shrink to their own content + the row mirrors, so the avatar sits on the right and the header/text shrink to their own content width against that same edge instead of stretching the full row. `.chat- block` (approve/connect-service/connect-github/poll/form/steps) and `.chat-trace` rows render as siblings of the bubble, not inside diff --git a/apps/web/src/chat/system-line.tsx b/apps/web/src/chat/system-line.tsx new file mode 100644 index 000000000..fe939fe1c --- /dev/null +++ b/apps/web/src/chat/system-line.tsx @@ -0,0 +1,6 @@ +import type { ReactNode } from "react"; + +// A quiet line between messages, e.g. "Voice with X · 3 turns". Wrap names in . +export function SystemLine({ children }: { readonly children: ReactNode }) { + return

{children}

; +} diff --git a/apps/web/src/pages/workbench-page.tsx b/apps/web/src/pages/workbench-page.tsx index dfefdf878..a64eb60be 100644 --- a/apps/web/src/pages/workbench-page.tsx +++ b/apps/web/src/pages/workbench-page.tsx @@ -69,6 +69,34 @@ function WorkbenchMessageRow({ // see echoed back at them. const body = message.author === "me" ? stripRoster(message.body) : message.body; const { pkg, renderedBody } = resolveMessagePackage(message.attachments, body); + const own = message.author === "me"; + const time = new Date(message.at); + const content = ( + <> + + + + ); + const reply = + onReply === undefined ? null : ( + + ); + if (own) { + return ( +
+
+
{content}
+ {reply} +
+
+ ); + } return (
@@ -79,17 +107,16 @@ function WorkbenchMessageRow({ />
- - - {onReply === undefined ? null : ( - - )} +
+ {avatarName} + {Number.isNaN(time.getTime()) ? null : ( + + )} +
+ {content} + {reply}
);