message-nav.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import { UserMessage } from "@opencode-ai/sdk"
  2. import { ComponentProps, createMemo, For, Match, Show, splitProps, Switch } from "solid-js"
  3. import { DiffChanges } from "./diff-changes"
  4. import { Spinner } from "./spinner"
  5. export function MessageNav(
  6. props: ComponentProps<"ul"> & {
  7. messages: UserMessage[]
  8. current?: UserMessage
  9. size: "normal" | "compact"
  10. working?: boolean
  11. onMessageSelect: (message: UserMessage) => void
  12. },
  13. ) {
  14. const [local, others] = splitProps(props, ["messages", "current", "size", "working", "onMessageSelect"])
  15. const lastUserMessage = createMemo(() => {
  16. return local.messages?.at(0)
  17. })
  18. return (
  19. <ul role="list" data-component="message-nav" data-size={local.size} {...others}>
  20. <For each={local.messages}>
  21. {(message) => {
  22. const messageWorking = createMemo(() => message.id === lastUserMessage()?.id && local.working)
  23. const handleClick = () => local.onMessageSelect(message)
  24. return (
  25. <li data-slot="message-nav-item">
  26. <Switch>
  27. <Match when={local.size === "compact"}>
  28. <button
  29. data-slot="message-nav-tick-button"
  30. data-active={message.id === local.current?.id || undefined}
  31. onClick={handleClick}
  32. >
  33. <div data-slot="message-nav-tick-line" />
  34. </button>
  35. </Match>
  36. <Match when={local.size === "normal"}>
  37. <button data-slot="message-nav-message-button" onClick={handleClick}>
  38. <Switch>
  39. <Match when={messageWorking()}>
  40. <Spinner />
  41. </Match>
  42. <Match when={true}>
  43. <DiffChanges changes={message.summary?.diffs ?? []} variant="bars" />
  44. </Match>
  45. </Switch>
  46. <div
  47. data-slot="message-nav-title-preview"
  48. data-active={message.id === local.current?.id || undefined}
  49. >
  50. <Show when={message.summary?.title} fallback="New message">
  51. {message.summary?.title}
  52. </Show>
  53. </div>
  54. </button>
  55. </Match>
  56. </Switch>
  57. </li>
  58. )
  59. }}
  60. </For>
  61. </ul>
  62. )
  63. }