feat(ui): switch message actions to icon buttons

This commit is contained in:
Shantur Rathore
2026-02-05 23:42:48 +00:00
parent 6c42b64466
commit 157fe9d6b4
2 changed files with 28 additions and 27 deletions

View File

@@ -1,5 +1,5 @@
import { For, Match, Show, Switch, createEffect, createMemo, createSignal, untrack } from "solid-js" import { For, Match, Show, Switch, createEffect, createMemo, createSignal, untrack } from "solid-js"
import { FoldVertical } from "lucide-solid" import { ExternalLink, FoldVertical, Trash2 } from "lucide-solid"
import MessageItem from "./message-item" import MessageItem from "./message-item"
import ToolCall from "./tool-call" import ToolCall from "./tool-call"
import type { InstanceMessageStore } from "../stores/message-v2/instance-store" import type { InstanceMessageStore } from "../stores/message-v2/instance-store"
@@ -390,9 +390,10 @@ function ToolCallItem(props: ToolCallItemProps) {
type="button" type="button"
disabled={!taskLocation()} disabled={!taskLocation()}
onClick={handleGoToTaskSession} onClick={handleGoToTaskSession}
title={!taskLocation() ? t("messageBlock.tool.goToSession.unavailableTitle") : t("messageBlock.tool.goToSession.title")} title={t("messageBlock.tool.goToSession.label")}
aria-label={t("messageBlock.tool.goToSession.label")}
> >
{t("messageBlock.tool.goToSession.label")} <ExternalLink class="w-3.5 h-3.5" aria-hidden="true" />
</button> </button>
</Show> </Show>
@@ -401,9 +402,10 @@ function ToolCallItem(props: ToolCallItemProps) {
type="button" type="button"
disabled={deleteDisabled()} disabled={deleteDisabled()}
onClick={handleDeleteToolPart} onClick={handleDeleteToolPart}
title={t("messageBlock.tool.deletePart.title")} title={deleting() ? t("messageBlock.tool.deletePart.deleting") : t("messageBlock.tool.deletePart.label")}
aria-label={deleting() ? t("messageBlock.tool.deletePart.deleting") : t("messageBlock.tool.deletePart.label")}
> >
{deleting() ? t("messageBlock.tool.deletePart.deleting") : t("messageBlock.tool.deletePart.label")} <Trash2 class="w-3.5 h-3.5" aria-hidden="true" />
</button> </button>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,5 @@
import { For, Show, createSignal } from "solid-js" import { For, Show, createSignal } from "solid-js"
import { Copy, Split, Trash2, Undo } from "lucide-solid"
import type { MessageInfo, ClientPart } from "../types/message" import type { MessageInfo, ClientPart } from "../types/message"
import { partHasRenderableText } from "../types/message" import { partHasRenderableText } from "../types/message"
import type { MessageRecord } from "../stores/message-v2/types" import type { MessageRecord } from "../stores/message-v2/types"
@@ -159,6 +160,8 @@ export default function MessageItem(props: MessageItemProps) {
} }
} }
const copyLabel = () => (copied() ? t("messageItem.actions.copied") : t("messageItem.actions.copy"))
const getRawContent = () => { const getRawContent = () => {
return props.parts return props.parts
.filter(part => part.type === "text") .filter(part => part.type === "text")
@@ -278,31 +281,29 @@ export default function MessageItem(props: MessageItemProps) {
<button <button
class="message-action-button" class="message-action-button"
onClick={handleRevert} onClick={handleRevert}
title={t("messageItem.actions.revertTitle")} title={t("messageItem.actions.revert")}
aria-label={t("messageItem.actions.revertTitle")} aria-label={t("messageItem.actions.revert")}
> >
{t("messageItem.actions.revert")} <Undo class="w-3.5 h-3.5" aria-hidden="true" />
</button> </button>
</Show> </Show>
<Show when={props.onFork}> <Show when={props.onFork}>
<button <button
class="message-action-button" class="message-action-button"
onClick={() => props.onFork?.(props.record.id)} onClick={() => props.onFork?.(props.record.id)}
title={t("messageItem.actions.forkTitle")} title={t("messageItem.actions.fork")}
aria-label={t("messageItem.actions.forkTitle")} aria-label={t("messageItem.actions.fork")}
> >
{t("messageItem.actions.fork")} <Split class="w-3.5 h-3.5" aria-hidden="true" />
</button> </button>
</Show> </Show>
<button <button
class="message-action-button" class="message-action-button"
onClick={handleCopy} onClick={handleCopy}
title={t("messageItem.actions.copyTitle")} title={copyLabel()}
aria-label={t("messageItem.actions.copyTitle")} aria-label={copyLabel()}
> >
<Show when={copied()} fallback={t("messageItem.actions.copy")}> <Copy class="w-3.5 h-3.5" aria-hidden="true" />
{t("messageItem.actions.copied")}
</Show>
</button> </button>
<Show when={deletableTextPartId()}> <Show when={deletableTextPartId()}>
{(partId) => ( {(partId) => (
@@ -310,10 +311,10 @@ export default function MessageItem(props: MessageItemProps) {
class="message-action-button" class="message-action-button"
onClick={() => void handleDeletePart(partId())} onClick={() => void handleDeletePart(partId())}
disabled={isDeletingPart(partId())} disabled={isDeletingPart(partId())}
title={t("messagePart.actions.deleteTitle")} title={isDeletingPart(partId()) ? t("messagePart.actions.deleting") : t("messagePart.actions.delete")}
aria-label={t("messagePart.actions.deleteTitle")} aria-label={isDeletingPart(partId()) ? t("messagePart.actions.deleting") : t("messagePart.actions.delete")}
> >
{isDeletingPart(partId()) ? t("messagePart.actions.deleting") : t("messagePart.actions.delete")} <Trash2 class="w-3.5 h-3.5" aria-hidden="true" />
</button> </button>
)} )}
</Show> </Show>
@@ -324,12 +325,10 @@ export default function MessageItem(props: MessageItemProps) {
<button <button
class="message-action-button" class="message-action-button"
onClick={handleCopy} onClick={handleCopy}
title={t("messageItem.actions.copyTitle")} title={copyLabel()}
aria-label={t("messageItem.actions.copyTitle")} aria-label={copyLabel()}
> >
<Show when={copied()} fallback={t("messageItem.actions.copy")}> <Copy class="w-3.5 h-3.5" aria-hidden="true" />
{t("messageItem.actions.copied")}
</Show>
</button> </button>
<Show when={deletableTextPartId()}> <Show when={deletableTextPartId()}>
@@ -338,10 +337,10 @@ export default function MessageItem(props: MessageItemProps) {
class="message-action-button" class="message-action-button"
onClick={() => void handleDeletePart(partId())} onClick={() => void handleDeletePart(partId())}
disabled={isDeletingPart(partId())} disabled={isDeletingPart(partId())}
title={t("messagePart.actions.deleteTitle")} title={isDeletingPart(partId()) ? t("messagePart.actions.deleting") : t("messagePart.actions.delete")}
aria-label={t("messagePart.actions.deleteTitle")} aria-label={isDeletingPart(partId()) ? t("messagePart.actions.deleting") : t("messagePart.actions.delete")}
> >
{isDeletingPart(partId()) ? t("messagePart.actions.deleting") : t("messagePart.actions.delete")} <Trash2 class="w-3.5 h-3.5" aria-hidden="true" />
</button> </button>
)} )}
</Show> </Show>