From cda289b8b1368a175c7d01e0a107a493a94041dc Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Sat, 23 May 2026 00:42:19 +0200 Subject: [PATCH] give Claude turns a brand-orange message card (T-144) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the card treatment to Claude's text responses: _userCard becomes a shared _messageCard(label, accent, body) used by both turns. The user stripe stays the theme focus colour; Claude's stripe + label use Claude's brand coral-orange (#D97757) — a fixed brand accent, not a theme token — so the two speakers are accent-coded at a glance. Co-Authored-By: Claude Opus 4.7 (1M context) --- .pql/changelog/ticket_history/2026-05.sql | 2 ++ .pql/changelog/tickets/2026-05.sql | 2 ++ CHANGELOG.md | 7 +++--- lib/builtin/claude/src/conversation_view.dart | 23 +++++++++++-------- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.pql/changelog/ticket_history/2026-05.sql b/.pql/changelog/ticket_history/2026-05.sql index 12a25e63..d3f0d5fa 100644 --- a/.pql/changelog/ticket_history/2026-05.sql +++ b/.pql/changelog/ticket_history/2026-05.sql @@ -2146,3 +2146,5 @@ INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-142', 'status', 'backlog', 'in_progress', NULL, '2026-05-22 22:09:09', '2026-05-22 22:09:09', '2026-05-22 22:09:09', NULL, 'b799657bf436bc44e306ef71658c80e5', 1) ON CONFLICT(hash) DO NOTHING; INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-142', 'status', 'in_progress', 'done', NULL, '2026-05-22 22:18:02', '2026-05-22 22:18:02', '2026-05-22 22:18:02', NULL, '374be08610920e404c8394bc10b1e12a', 1) ON CONFLICT(hash) DO NOTHING; INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-143', 'status', 'backlog', 'in_progress', NULL, '2026-05-22 22:31:25', '2026-05-22 22:31:25', '2026-05-22 22:31:25', NULL, 'e2a16eb8af0afc30a5d0fc88c523e507', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-143', 'status', 'in_progress', 'done', NULL, '2026-05-22 22:36:09', '2026-05-22 22:36:09', '2026-05-22 22:36:09', NULL, '9b8859ea2e8db7083bfb9d2ab17c1c57', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-144', 'status', 'backlog', 'in_progress', NULL, '2026-05-22 22:41:28', '2026-05-22 22:41:28', '2026-05-22 22:41:28', NULL, 'eda6f75e88401ee5b445e7edfc312f82', 1) ON CONFLICT(hash) DO NOTHING; diff --git a/.pql/changelog/tickets/2026-05.sql b/.pql/changelog/tickets/2026-05.sql index ad08139d..6ea891ed 100644 --- a/.pql/changelog/tickets/2026-05.sql +++ b/.pql/changelog/tickets/2026-05.sql @@ -2491,3 +2491,5 @@ INSERT INTO tickets (id, type, parent_id, title, description, status, priority, INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-142', 'task', 'T-132', 'Composer attachment chips (thumbnail/icon on paste)', 'Show pasted files/images as chips above the composer input instead of inserting the @path as text. Image chips render a thumbnail (Image.file of the cache/temp file); other types show a Phosphor file icon + basename; each chip has a remove ×. On submit, the typed text plus the chips'' @path tokens are assembled into the message sent via tmux.sendMessage, then text + chips clear. Typed @path text still works. resolveClipboardAttachment changes to return a list of attachment descriptors (path + isImage). No new package deps (Image.file + existing Phosphor icons). Builds on T-138.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-05-22 22:06:59', '2026-05-22 22:09:09', NULL, 'da746aa3a523e3b351eaa13f19fa51e1', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-142', 'task', 'T-132', 'Composer attachment chips (thumbnail/icon on paste)', 'Show pasted files/images as chips above the composer input instead of inserting the @path as text. Image chips render a thumbnail (Image.file of the cache/temp file); other types show a Phosphor file icon + basename; each chip has a remove ×. On submit, the typed text plus the chips'' @path tokens are assembled into the message sent via tmux.sendMessage, then text + chips clear. Typed @path text still works. resolveClipboardAttachment changes to return a list of attachment descriptors (path + isImage). No new package deps (Image.file + existing Phosphor icons). Builds on T-138.', 'done', 'medium', NULL, NULL, NULL, '2026-05-22 22:06:59', '2026-05-22 22:18:02', NULL, '384c57378557c6f32f2cf93af99873c4', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-143', 'task', 'T-132', 'Distinguish user message cards in the conversation', 'User messages render flat (label + text on the canvas) like Claude''s responses, so it''s hard to scan what you said vs what Claude said. Give UserMessage a distinct card: a filled background (globalBackground vs the panelBackground canvas), a left accent stripe (globalFocus), padding and rounded corners. Claude''s text responses stay flat markdown (better for long answers). conversation_view.dart _ConversationTurn.', 'in_progress', 'low', NULL, NULL, NULL, '2026-05-22 22:31:22', '2026-05-22 22:31:25', NULL, 'efa90d878f79235f81d54d00c04014c8', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-143', 'task', 'T-132', 'Distinguish user message cards in the conversation', 'User messages render flat (label + text on the canvas) like Claude''s responses, so it''s hard to scan what you said vs what Claude said. Give UserMessage a distinct card: a filled background (globalBackground vs the panelBackground canvas), a left accent stripe (globalFocus), padding and rounded corners. Claude''s text responses stay flat markdown (better for long answers). conversation_view.dart _ConversationTurn.', 'done', 'low', NULL, NULL, NULL, '2026-05-22 22:31:22', '2026-05-22 22:36:09', NULL, '11ebd7f43b4371b15acb0729010cdec9', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-144', 'task', 'T-132', 'Claude message card with brand-orange accent', 'Extend the distinct-card treatment (T-143) to Claude''s text responses with a different accent: Claude''s brand coral-orange (#D97757), vs the user card''s focus-colour stripe. Refactor _userCard into a shared _messageCard(label, accent, body). conversation_view.dart.', 'in_progress', 'low', NULL, NULL, NULL, '2026-05-22 22:40:42', '2026-05-22 22:41:28', NULL, '4c0eebba4edb4394fb47ba2d81ef42ad', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ba345b5..8f7c8520 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,9 +86,10 @@ heading, and (b) bumping `pubspec.yaml` `version:` in the same commit. ### Changed -- User messages in the Claude conversation now render as a distinct card - (accent stripe + filled background) so your prompts read apart from - Claude's flat-markdown responses (T-143). +- User and Claude turns in the conversation now render as distinct + accent-striped cards over a filled background — your prompts in the + theme focus colour, Claude's replies in Claude's brand orange + (T-143, T-144). - Claude conversation content now flows through the kernel MessageBus — a reader tails the transcript and publishes items; the pane subscribes. Decouples reading from rendering so the upcoming team panels can show diff --git a/lib/builtin/claude/src/conversation_view.dart b/lib/builtin/claude/src/conversation_view.dart index 98f02765..c63aa0c8 100644 --- a/lib/builtin/claude/src/conversation_view.dart +++ b/lib/builtin/claude/src/conversation_view.dart @@ -94,6 +94,10 @@ class _ConversationViewState extends State { } } +/// Claude's brand coral-orange — a fixed brand accent (not a theme token) +/// used for the "claude" message card's stripe + label. +const claudeAccent = Color(0xFFD97757); + /// One conversation item, rendered by kind. class _ConversationTurn extends StatelessWidget { const _ConversationTurn({required this.item, required this.tokens}); @@ -105,8 +109,8 @@ class _ConversationTurn extends StatelessWidget { Widget build(BuildContext context) { final i = item; return switch (i) { - UserMessage() => _userCard(i), - AssistantTextMessage() => _labelled('claude', tokens.globalFocus, ClideMarkdown(i.text)), + UserMessage() => _messageCard('you', tokens.globalFocus, ClideMarkdown(i.text)), + AssistantTextMessage() => _messageCard('claude', claudeAccent, ClideMarkdown(i.text)), AssistantThinkingMessage() => _labelled( 'thinking', tokens.globalTextMuted, @@ -117,9 +121,10 @@ class _ConversationTurn extends StatelessWidget { }; } - /// The user's own message — a distinct card (accent stripe + fill) so - /// it reads apart from Claude's flat-markdown responses. - Widget _userCard(UserMessage m) { + /// A turn rendered as a distinct card: an [accent]-coloured left stripe + /// and label over a filled background, so user and Claude turns read + /// apart from each other (and from the panel canvas) by accent. + Widget _messageCard(String label, Color accent, Widget body) { return Padding( padding: const EdgeInsets.only(bottom: 14), child: ClipRRect( @@ -130,7 +135,7 @@ class _ConversationTurn extends StatelessWidget { child: Row( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Container(width: 3, color: tokens.globalFocus), + Container(width: 3, color: accent), Expanded( child: Padding( padding: const EdgeInsets.fromLTRB(12, 8, 12, 8), @@ -138,13 +143,13 @@ class _ConversationTurn extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ ClideText( - 'you', + label, fontSize: clideFontSmall, - color: tokens.globalFocus, + color: accent, fontFamily: clideMonoFamily, ), const SizedBox(height: 4), - ClideMarkdown(m.text), + body, ], ), ),