opencode/packages/ui/src/components/message-nav.tsx

88 lines
3.2 KiB
TypeScript
Raw Normal View History

2025-12-10 04:49:00 +08:00
import { UserMessage } from "@opencode-ai/sdk/v2"
2025-12-12 04:46:29 +08:00
import { ComponentProps, For, Match, Show, splitProps, Switch } from "solid-js"
2025-11-23 08:17:45 +08:00
import { DiffChanges } from "./diff-changes"
2025-11-25 01:56:00 +08:00
import { Tooltip } from "@kobalte/core/tooltip"
2026-01-21 05:42:10 +08:00
import { useI18n } from "../context/i18n"
2025-11-23 08:17:45 +08:00
export function MessageNav(
props: ComponentProps<"ul"> & {
messages: UserMessage[]
current?: UserMessage
size: "normal" | "compact"
onMessageSelect: (message: UserMessage) => void
2026-01-16 03:32:15 +08:00
getLabel?: (message: UserMessage) => string | undefined
2025-11-23 08:17:45 +08:00
},
) {
2026-01-21 05:42:10 +08:00
const i18n = useI18n()
2026-01-16 03:32:15 +08:00
const [local, others] = splitProps(props, ["messages", "current", "size", "onMessageSelect", "getLabel"])
2025-11-23 08:17:45 +08:00
2025-11-25 04:52:32 +08:00
const content = () => (
2025-11-23 08:17:45 +08:00
<ul role="list" data-component="message-nav" data-size={local.size} {...others}>
<For each={local.messages}>
{(message) => {
const handleClick = () => local.onMessageSelect(message)
2026-01-16 03:32:15 +08:00
const handleKeyPress = (event: KeyboardEvent) => {
if (event.key !== "Enter" && event.key !== " ") return
event.preventDefault()
local.onMessageSelect(message)
}
2025-11-23 08:17:45 +08:00
return (
<li data-slot="message-nav-item">
<Switch>
<Match when={local.size === "compact"}>
2026-01-16 03:32:15 +08:00
<div
data-slot="message-nav-tick-button"
data-active={message.id === local.current?.id || undefined}
role="button"
tabindex={0}
onClick={handleClick}
onKeyDown={handleKeyPress}
>
2025-11-23 08:17:45 +08:00
<div data-slot="message-nav-tick-line" />
2025-11-25 01:56:00 +08:00
</div>
2025-11-23 08:17:45 +08:00
</Match>
<Match when={local.size === "normal"}>
2026-01-16 03:32:15 +08:00
<button data-slot="message-nav-message-button" onClick={handleClick} onKeyDown={handleKeyPress}>
2025-12-12 04:46:29 +08:00
<DiffChanges changes={message.summary?.diffs ?? []} variant="bars" />
2025-11-23 08:17:45 +08:00
<div
data-slot="message-nav-title-preview"
data-active={message.id === local.current?.id || undefined}
>
2026-01-21 05:42:10 +08:00
<Show
when={local.getLabel?.(message) ?? message.summary?.title}
fallback={i18n.t("ui.messageNav.newMessage")}
>
2026-01-16 03:32:15 +08:00
{local.getLabel?.(message) ?? message.summary?.title}
2025-11-23 08:17:45 +08:00
</Show>
</div>
</button>
</Match>
</Switch>
</li>
)
}}
</For>
</ul>
)
2025-11-25 01:56:00 +08:00
return (
<Switch>
<Match when={local.size === "compact"}>
2025-12-12 04:52:01 +08:00
<Tooltip openDelay={0} closeDelay={300} placement="right-start" gutter={-40} shift={-10} overlap>
2025-11-25 04:52:32 +08:00
<Tooltip.Trigger as="div">{content()}</Tooltip.Trigger>
2025-11-25 01:56:00 +08:00
<Tooltip.Portal>
<Tooltip.Content data-slot="message-nav-tooltip">
<div data-slot="message-nav-tooltip-content">
2025-11-25 07:59:34 +08:00
<MessageNav {...props} size="normal" class="" />
2025-11-25 01:56:00 +08:00
</div>
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip>
</Match>
2025-11-25 04:52:32 +08:00
<Match when={local.size === "normal"}>{content()}</Match>
2025-11-25 01:56:00 +08:00
</Switch>
)
2025-11-23 08:17:45 +08:00
}