message-nav.tsx 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import { UserMessage } from "@opencode-ai/sdk/v2"
  2. import { ComponentProps, For, Match, Show, splitProps, Switch } from "solid-js"
  3. import { DiffChanges } from "./diff-changes"
  4. import { Tooltip } from "./tooltip"
  5. import { useI18n } from "../context/i18n"
  6. export function MessageNav(
  7. props: ComponentProps<"ul"> & {
  8. messages: UserMessage[]
  9. current?: UserMessage
  10. size: "normal" | "compact"
  11. onMessageSelect: (message: UserMessage) => void
  12. getLabel?: (message: UserMessage) => string | undefined
  13. },
  14. ) {
  15. const i18n = useI18n()
  16. const [local, others] = splitProps(props, ["messages", "current", "size", "onMessageSelect", "getLabel"])
  17. const content = () => (
  18. <ul role="list" data-component="message-nav" data-size={local.size} {...others}>
  19. <For each={local.messages}>
  20. {(message) => {
  21. const handleClick = () => local.onMessageSelect(message)
  22. const handleKeyPress = (event: KeyboardEvent) => {
  23. if (event.key !== "Enter" && event.key !== " ") return
  24. event.preventDefault()
  25. local.onMessageSelect(message)
  26. }
  27. return (
  28. <li data-slot="message-nav-item">
  29. <Switch>
  30. <Match when={local.size === "compact"}>
  31. <div
  32. data-slot="message-nav-tick-button"
  33. data-active={message.id === local.current?.id || undefined}
  34. role="button"
  35. tabindex={0}
  36. onClick={handleClick}
  37. onKeyDown={handleKeyPress}
  38. >
  39. <div data-slot="message-nav-tick-line" />
  40. </div>
  41. </Match>
  42. <Match when={local.size === "normal"}>
  43. <button data-slot="message-nav-message-button" onClick={handleClick} onKeyDown={handleKeyPress}>
  44. <DiffChanges changes={message.summary?.diffs ?? []} variant="bars" />
  45. <div
  46. data-slot="message-nav-title-preview"
  47. data-active={message.id === local.current?.id || undefined}
  48. >
  49. <Show
  50. when={local.getLabel?.(message) ?? message.summary?.title}
  51. fallback={i18n.t("ui.messageNav.newMessage")}
  52. >
  53. {local.getLabel?.(message) ?? message.summary?.title}
  54. </Show>
  55. </div>
  56. </button>
  57. </Match>
  58. </Switch>
  59. </li>
  60. )
  61. }}
  62. </For>
  63. </ul>
  64. )
  65. return (
  66. <Switch>
  67. <Match when={local.size === "compact"}>
  68. <Tooltip
  69. openDelay={0}
  70. placement="right-start"
  71. gutter={-40}
  72. shift={-10}
  73. overlap
  74. contentClass="message-nav-tooltip"
  75. value={
  76. <div data-slot="message-nav-tooltip-content">
  77. <MessageNav {...props} size="normal" class="" />
  78. </div>
  79. }
  80. >
  81. {content()}
  82. </Tooltip>
  83. </Match>
  84. <Match when={local.size === "normal"}>{content()}</Match>
  85. </Switch>
  86. )
  87. }