-
Notifications
You must be signed in to change notification settings - Fork 17.7k
Expand file tree
/
Copy pathmessage-nav.tsx
More file actions
125 lines (114 loc) · 4.13 KB
/
message-nav.tsx
File metadata and controls
125 lines (114 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { UserMessage } from "@opencode-ai/sdk/v2"
import { ComponentProps, For, Match, Show, createSignal, onCleanup, splitProps, Switch } from "solid-js"
import { DiffChanges } from "./diff-changes"
import { useI18n } from "../context/i18n"
export function MessageNav(
props: ComponentProps<"ul"> & {
messages: UserMessage[]
current?: UserMessage
size: "normal" | "compact"
onMessageSelect: (message: UserMessage) => void
getLabel?: (message: UserMessage) => string | undefined
},
) {
const i18n = useI18n()
const [local, others] = splitProps(props, ["messages", "current", "size", "onMessageSelect", "getLabel", "class"])
let closeTimer: number | undefined
const clearCloseTimer = () => {
if (!closeTimer) return
clearTimeout(closeTimer)
closeTimer = undefined
}
const [hovercardOpen, setHovercardOpen] = createSignal(false)
onCleanup(clearCloseTimer)
const showHovercard = () => {
clearCloseTimer()
setHovercardOpen(true)
}
const hideHovercard = () => {
clearCloseTimer()
closeTimer = window.setTimeout(() => {
setHovercardOpen(false)
closeTimer = undefined
}, 120) as unknown as number
}
const selectMessage = (message: UserMessage) => {
clearCloseTimer()
setHovercardOpen(false)
local.onMessageSelect(message)
}
const content = (className?: string) => (
<ul role="list" data-component="message-nav" data-size={local.size} class={className} {...others}>
<For each={local.messages}>
{(message) => {
const handleClick = () => selectMessage(message)
const handleKeyPress = (event: KeyboardEvent) => {
if (event.key !== "Enter" && event.key !== " ") return
event.preventDefault()
selectMessage(message)
}
return (
<li data-slot="message-nav-item">
<Switch>
<Match when={local.size === "compact"}>
<div
data-slot="message-nav-tick-button"
data-active={message.id === local.current?.id || undefined}
role="button"
tabindex={0}
onClick={handleClick}
onKeyDown={handleKeyPress}
>
<div data-slot="message-nav-tick-line" />
</div>
</Match>
<Match when={local.size === "normal"}>
<button data-slot="message-nav-message-button" onClick={handleClick} onKeyDown={handleKeyPress}>
<DiffChanges changes={message.summary?.diffs ?? []} variant="bars" />
<div
data-slot="message-nav-title-preview"
data-active={message.id === local.current?.id || undefined}
>
<Show
when={local.getLabel?.(message) ?? message.summary?.title}
fallback={i18n.t("ui.messageNav.newMessage")}
>
{local.getLabel?.(message) ?? message.summary?.title}
</Show>
</div>
</button>
</Match>
</Switch>
</li>
)
}}
</For>
</ul>
)
return (
<Switch>
<Match when={local.size === "compact"}>
<div
data-component="message-nav-hovercard"
class={local.class}
onPointerEnter={showHovercard}
onPointerLeave={hideHovercard}
onFocusIn={showHovercard}
onFocusOut={(event) => {
const next = event.relatedTarget
if (next instanceof Node && event.currentTarget.contains(next)) return
hideHovercard()
}}
>
{content()}
<Show when={hovercardOpen()}>
<div class="message-nav-tooltip" data-slot="message-nav-tooltip-content">
<MessageNav {...props} size="normal" class="" onMessageSelect={selectMessage} />
</div>
</Show>
</div>
</Match>
<Match when={local.size === "normal"}>{content(local.class)}</Match>
</Switch>
)
}