From 635cb6de7342ac87b27243652b1ad3b3a133d6a4 Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Sun, 7 Jun 2026 15:27:58 +0900 Subject: feat(chat): restyle transcript — left-aligned, bubbleless assistant, tool cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All messages flow left in one column via the DaisyUI chat-start grid: - user keeps a primary speech bubble; - assistant/system/error render in a transparent (invisible) chat-bubble so they read as plain prose yet inherit identical left spacing, capped to a readable max-w-5xl column; - tool call/result render as regular (non-speech) rounded cards, nested in the same grid so they line up too; - role header labels dropped; chat-wide left padding added. Alignment uses specificity-based variants (no !important). --- src/features/chat/ui.test.ts | 7 +-- src/features/chat/ui/ChatView.svelte | 97 +++++++++++++++++++++++------------- 2 files changed, 65 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/features/chat/ui.test.ts b/src/features/chat/ui.test.ts index ac8f640..2099257 100644 --- a/src/features/chat/ui.test.ts +++ b/src/features/chat/ui.test.ts @@ -20,7 +20,6 @@ describe("ChatView", () => { render(ChatView, { props: { chunks } }); expect(screen.getByText("Hello world")).toBeInTheDocument(); - expect(screen.getByText("assistant")).toBeInTheDocument(); }); it("renders multiple chunks", () => { @@ -145,8 +144,10 @@ describe("ChatView", () => { render(ChatView, { props: { chunks } }); - const bubble = screen.getByText("Streaming...").closest(".chat-bubble"); - expect(bubble).toHaveClass("opacity-50"); + // Assistant chunks are no longer in a bubble; the provisional marker now + // lives on the plain wrapper that directly contains the text. + const wrapper = screen.getByText("Streaming...").closest("div"); + expect(wrapper).toHaveClass("opacity-50"); }); it("renders empty transcript", () => { diff --git a/src/features/chat/ui/ChatView.svelte b/src/features/chat/ui/ChatView.svelte index cb6069b..0234852 100644 --- a/src/features/chat/ui/ChatView.svelte +++ b/src/features/chat/ui/ChatView.svelte @@ -4,44 +4,69 @@ let { chunks }: { chunks: readonly RenderedChunk[] } = $props(); -
+
{#each chunks as rendered, i (rendered.seq != null ? `c${rendered.seq}` : `p${i}`)} -
-
{rendered.role}
-
- {#if rendered.chunk.type === "text"} -

{rendered.chunk.text}

- {:else if rendered.chunk.type === "thinking"} -
- Thinking + {#if rendered.role === "user"} + +
+
+ {#if rendered.chunk.type === "text"}

{rendered.chunk.text}

-
- {:else if rendered.chunk.type === "tool-call"} -
- {rendered.chunk.toolName} -
{JSON.stringify(rendered.chunk.input, null, 2)}
-
- {:else if rendered.chunk.type === "tool-result"} -
- {rendered.chunk.toolName} -
{rendered.chunk.content}
-
- {:else if rendered.chunk.type === "error"} - - {:else if rendered.chunk.type === "system"} -
{rendered.chunk.text}
- {/if} + {/if} +
-
+ {:else if rendered.chunk.type === "tool-call" || rendered.chunk.type === "tool-result"} + +
+
+ {#if rendered.chunk.type === "tool-call"} +
+ {rendered.chunk.toolName} +
{JSON.stringify(rendered.chunk.input, null, 2)}
+
+ {:else} +
+ {rendered.chunk.toolName} +
{rendered.chunk.content}
+
+ {/if} +
+
+ {:else} + +
+
+ {#if rendered.chunk.type === "text"} +

{rendered.chunk.text}

+ {:else if rendered.chunk.type === "thinking"} +
+ Thinking +

{rendered.chunk.text}

+
+ {:else if rendered.chunk.type === "error"} + + {:else if rendered.chunk.type === "system"} +
{rendered.chunk.text}
+ {/if} +
+
+ {/if} {/each}
-- cgit v1.2.3