|
| 1 | +import { TextAttributes } from '@opentui/core' |
1 | 2 | import React, { useRef, useState } from 'react' |
2 | 3 | import stringWidth from 'string-width' |
3 | 4 |
|
@@ -41,6 +42,7 @@ export const AgentModeToggle = ({ |
41 | 42 | const [isOpen, setIsOpen] = useState(false) |
42 | 43 | const closeTimeoutRef = useRef<NodeJS.Timeout | null>(null) |
43 | 44 | const openTimeoutRef = useRef<NodeJS.Timeout | null>(null) |
| 45 | + const [hoveredIndex, setHoveredIndex] = useState<number>(ALL_MODES.length) |
44 | 46 |
|
45 | 47 | const handlePress = (selectedMode: AgentMode) => { |
46 | 48 | // Cancel any pending open timeout - click should be immediate |
@@ -88,6 +90,7 @@ export const AgentModeToggle = ({ |
88 | 90 | closeTimeoutRef.current = setTimeout(() => { |
89 | 91 | setIsOpen(false) |
90 | 92 | closeTimeoutRef.current = null |
| 93 | + setHoveredIndex(ALL_MODES.length) |
91 | 94 | }, 100) |
92 | 95 | } |
93 | 96 |
|
@@ -150,7 +153,7 @@ export const AgentModeToggle = ({ |
150 | 153 | const { frameColor, textColor, label } = config[modeItem] |
151 | 154 | const isActive = isLast |
152 | 155 | const width = segmentWidths[index] |
153 | | - const content = isActive ? ` < ${label} ` : ` ${label} ` |
| 156 | + const content = isLast ? ` < ${label} ` : ` ${label} ` |
154 | 157 | const horizontal = '─'.repeat(width) |
155 | 158 |
|
156 | 159 | return { |
@@ -179,64 +182,57 @@ export const AgentModeToggle = ({ |
179 | 182 | onMouseOver={handleMouseOver} |
180 | 183 | onMouseOut={handleMouseOut} |
181 | 184 | > |
182 | | - {/* Left edge */} |
183 | | - <box style={{ flexDirection: 'column', gap: 0 }}> |
184 | | - <text> |
185 | | - <span fg={segments[0].frameColor}>╭</span> |
186 | | - </text> |
187 | | - <text> |
188 | | - <span fg={segments[0].frameColor}>│</span> |
189 | | - </text> |
190 | | - <text> |
191 | | - <span fg={segments[0].frameColor}>╰</span> |
192 | | - </text> |
193 | | - </box> |
194 | | - |
195 | 185 | {/* Segments as vertical columns */} |
196 | 186 | {segments.map((seg, idx) => { |
197 | 187 | const modeItem = orderedModes[idx] |
198 | | - const isLast = idx === segments.length - 1 |
| 188 | + const leftOfHovered = idx <= hoveredIndex |
| 189 | + const rightOfHovered = idx >= hoveredIndex |
| 190 | + |
199 | 191 | return ( |
200 | 192 | <React.Fragment key={`segment-${idx}`}> |
201 | 193 | <box |
202 | 194 | onMouseDown={() => handlePress(modeItem)} |
| 195 | + onMouseOver={() => setHoveredIndex(idx)} |
203 | 196 | style={{ |
204 | | - flexDirection: 'column', |
| 197 | + flexDirection: 'row', |
205 | 198 | gap: 0, |
206 | | - width: seg.width, |
207 | | - minWidth: seg.width, |
208 | 199 | }} |
209 | 200 | > |
210 | | - <text> |
211 | | - <span fg={seg.frameColor}>{seg.topBorder}</span> |
212 | | - </text> |
213 | | - <text> |
214 | | - {seg.isActive ? ( |
215 | | - <> |
216 | | - <span fg={seg.textColor}> {'< '}</span> |
217 | | - <b> |
218 | | - <span fg={seg.textColor}>{seg.label}</span> |
219 | | - </b> |
220 | | - <span fg={seg.textColor}> </span> |
221 | | - </> |
222 | | - ) : ( |
223 | | - <span fg={seg.textColor}>{seg.content}</span> |
224 | | - )} |
225 | | - </text> |
226 | | - <text> |
227 | | - <span fg={seg.frameColor}>{seg.bottomBorder}</span> |
228 | | - </text> |
229 | | - </box> |
230 | | - <box style={{ flexDirection: 'column', gap: 0 }}> |
231 | | - <text> |
232 | | - <span fg={seg.frameColor}>╮</span> |
233 | | - </text> |
234 | | - <text> |
235 | | - <span fg={seg.frameColor}>│</span> |
236 | | - </text> |
237 | | - <text> |
238 | | - <span fg={seg.frameColor}>╯</span> |
239 | | - </text> |
| 201 | + { |
| 202 | + /* Left edge */ |
| 203 | + leftOfHovered ? ( |
| 204 | + <box style={{ flexDirection: 'column', gap: 0, maxWidth: 1 }}> |
| 205 | + <text fg={seg.frameColor}>╭│╰</text> |
| 206 | + </box> |
| 207 | + ) : null |
| 208 | + } |
| 209 | + { |
| 210 | + /* Segments as vertical columns for sorting */ |
| 211 | + <box> |
| 212 | + <text> |
| 213 | + <span fg={seg.frameColor}>{seg.topBorder}</span> |
| 214 | + </text> |
| 215 | + <text |
| 216 | + attributes={ |
| 217 | + idx === hoveredIndex ? TextAttributes.BOLD : undefined |
| 218 | + } |
| 219 | + fg={seg.textColor} |
| 220 | + > |
| 221 | + {seg.isActive ? ` < ${seg.label} ` : seg.content} |
| 222 | + </text> |
| 223 | + <text> |
| 224 | + <span fg={seg.frameColor}>{seg.bottomBorder}</span> |
| 225 | + </text> |
| 226 | + </box> |
| 227 | + } |
| 228 | + { |
| 229 | + /* Right edge */ |
| 230 | + rightOfHovered ? ( |
| 231 | + <box style={{ flexDirection: 'column', gap: 0, maxWidth: 1 }}> |
| 232 | + <text fg={seg.frameColor}>╮│╯</text> |
| 233 | + </box> |
| 234 | + ) : null |
| 235 | + } |
240 | 236 | </box> |
241 | 237 | </React.Fragment> |
242 | 238 | ) |
|
0 commit comments