FN-9199: Replace chat text back marker with arrow icon
Use a consistent icon-and-label back affordance across direct and room chat threads. - Render the lucide ArrowLeft icon with localized Back text and preserved accessible naming. - Cover mobile direct and room thread back buttons with icon, text, and accessibility assertions. - Add a patch changeset for the published Fusion package. Files changed: .changeset/fix-chat-back-arrow.md | 6 ++++++ packages/dashboard/app/components/ChatView.css | 2 +- packages/dashboard/app/components/ChatView.tsx | 14 ++++++++++++-- .../app/components/__tests__/ChatView.mobile.test.tsx | 4 +++- .../app/components/__tests__/ChatView.rooms.test.tsx | 7 ++++++- 5 files changed, 28 insertions(+), 5 deletions(-) Fusion-Task-Id: FN-9199 Fusion-Task-Lineage: aab2a300-cc2a-4768-b60b-81d7477b8fab Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
6
.changeset/fix-chat-back-arrow.md
Normal file
6
.changeset/fix-chat-back-arrow.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@runfusion/fusion": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
summary: Chat's back button now shows a real back arrow icon instead of a text character.
|
||||||
|
category: fix
|
||||||
@@ -2181,7 +2181,7 @@ Thinking-section text uses the defined muted text token across all themes. The m
|
|||||||
visible, the thread is hidden; when the sidebar is hidden (a session is
|
visible, the thread is hidden; when the sidebar is hidden (a session is
|
||||||
open), the sidebar is collapsed via .chat-sidebar--hidden and the
|
open), the sidebar is collapsed via .chat-sidebar--hidden and the
|
||||||
thread takes the full viewport. The thread already renders a back
|
thread takes the full viewport. The thread already renders a back
|
||||||
button (ChevronLeft) on mobile to flip back to the session list. */
|
button (ArrowLeft) on mobile to flip back to the session list. */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
html[data-viewport-mode="tablet"] .chat-view--docked-list .chat-view__body {
|
html[data-viewport-mode="tablet"] .chat-view--docked-list .chat-view__body {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
Search,
|
Search,
|
||||||
Trash2,
|
Trash2,
|
||||||
Archive,
|
Archive,
|
||||||
|
ArrowLeft,
|
||||||
Pencil,
|
Pencil,
|
||||||
Bot,
|
Bot,
|
||||||
Paperclip,
|
Paperclip,
|
||||||
@@ -3911,6 +3912,13 @@ export function ChatView({ projectId, addToast, floating = false, compactLayout
|
|||||||
{rooms.activeRoom ? (
|
{rooms.activeRoom ? (
|
||||||
<>
|
<>
|
||||||
<div className="chat-room-thread-header">
|
<div className="chat-room-thread-header">
|
||||||
|
{/*
|
||||||
|
FNXC:ChatNavigation 2026-08-23-15:54:
|
||||||
|
FN-9199 requires the chat detail Back affordance to render a real lucide ArrowLeft
|
||||||
|
glyph, never a literal less-than text character. Both Rooms and Direct thread
|
||||||
|
headers use this same icon-and-translated-label pattern on every chat host and
|
||||||
|
breakpoint, while aria-label retains the fuller accessible name.
|
||||||
|
*/}
|
||||||
{!dockedSidebarVisible ? <button
|
{!dockedSidebarVisible ? <button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-sm chat-thread-header-back chat-back-btn"
|
className="btn btn-sm chat-thread-header-back chat-back-btn"
|
||||||
@@ -3918,7 +3926,8 @@ export function ChatView({ projectId, addToast, floating = false, compactLayout
|
|||||||
data-testid="chat-back-btn"
|
data-testid="chat-back-btn"
|
||||||
aria-label={t("chat.backToConversations", "Back to conversations")}
|
aria-label={t("chat.backToConversations", "Back to conversations")}
|
||||||
>
|
>
|
||||||
{"< BACK"}
|
<ArrowLeft size={14} aria-hidden="true" />
|
||||||
|
<span>{t("chat.back", "Back")}</span>
|
||||||
</button> : null}
|
</button> : null}
|
||||||
<span className="chat-thread-header-title">#{rooms.activeRoom.name}</span>
|
<span className="chat-thread-header-title">#{rooms.activeRoom.name}</span>
|
||||||
<div className="chat-room-thread-members">
|
<div className="chat-room-thread-members">
|
||||||
@@ -4131,7 +4140,8 @@ export function ChatView({ projectId, addToast, floating = false, compactLayout
|
|||||||
data-testid="chat-back-btn"
|
data-testid="chat-back-btn"
|
||||||
aria-label={t("chat.backToConversations", "Back to conversations")}
|
aria-label={t("chat.backToConversations", "Back to conversations")}
|
||||||
>
|
>
|
||||||
{"< BACK"}
|
<ArrowLeft size={14} aria-hidden="true" />
|
||||||
|
<span>{t("chat.back", "Back")}</span>
|
||||||
</button> : null}
|
</button> : null}
|
||||||
<div className="chat-thread-header-identity" data-testid="chat-thread-header-identity">
|
<div className="chat-thread-header-identity" data-testid="chat-thread-header-identity">
|
||||||
{activeModelProvider ? <ProviderIcon provider={activeModelProvider} size="md" /> : <Bot size={16} />}
|
{activeModelProvider ? <ProviderIcon provider={activeModelProvider} size="md" /> : <Bot size={16} />}
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ describe("ChatView mobile list/detail navigation", () => {
|
|||||||
expect(sidebar).toHaveClass("chat-sidebar--hidden");
|
expect(sidebar).toHaveClass("chat-sidebar--hidden");
|
||||||
const back = screen.getByTestId("chat-back-btn");
|
const back = screen.getByTestId("chat-back-btn");
|
||||||
expect(back).toHaveAccessibleName("Back to conversations");
|
expect(back).toHaveAccessibleName("Back to conversations");
|
||||||
expect(back).toHaveTextContent("< BACK");
|
expect(back.textContent ?? "").not.toContain("<");
|
||||||
|
expect(back.querySelector("svg")).toBeInTheDocument();
|
||||||
|
expect(back).toHaveTextContent("Back");
|
||||||
expect(back.closest(".chat-thread-header")).toBeInTheDocument();
|
expect(back.closest(".chat-thread-header")).toBeInTheDocument();
|
||||||
expect(back.closest(".view-header")).toBeNull();
|
expect(back.closest(".view-header")).toBeNull();
|
||||||
expect(screen.getAllByTestId("chat-back-btn")).toHaveLength(1);
|
expect(screen.getAllByTestId("chat-back-btn")).toHaveLength(1);
|
||||||
|
|||||||
@@ -777,7 +777,12 @@ describe("ChatView — rooms (FN-3805..FN-3811 contract)", () => {
|
|||||||
await renderRoomDetailWithAct(<ChatView projectId="proj-123" addToast={vi.fn()} experimentalFeatures={{ chatRooms: true }} />);
|
await renderRoomDetailWithAct(<ChatView projectId="proj-123" addToast={vi.fn()} experimentalFeatures={{ chatRooms: true }} />);
|
||||||
await userEvent.click(screen.getByTestId("chat-room-item-room-a"));
|
await userEvent.click(screen.getByTestId("chat-room-item-room-a"));
|
||||||
|
|
||||||
expect(screen.getByTestId("chat-back-btn")).toBeInTheDocument();
|
const back = screen.getByTestId("chat-back-btn");
|
||||||
|
expect(back).toBeInTheDocument();
|
||||||
|
expect(back).toHaveAccessibleName("Back to conversations");
|
||||||
|
expect(back.textContent ?? "").not.toContain("<");
|
||||||
|
expect(back.querySelector("svg")).toBeInTheDocument();
|
||||||
|
expect(back).toHaveTextContent("Back");
|
||||||
mediaSpy.mockRestore();
|
mediaSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user