renderResizeHandle renders the draggable separator between content and bottom panel.
(width int)
| 2480 | |
| 2481 | // renderResizeHandle renders the draggable separator between content and bottom panel. |
| 2482 | func (m *appModel) renderResizeHandle(width int) string { |
| 2483 | if width <= 0 { |
| 2484 | return "" |
| 2485 | } |
| 2486 | |
| 2487 | innerWidth := width - appPaddingHorizontal |
| 2488 | |
| 2489 | // Use brighter style when actively dragging |
| 2490 | centerStyle := styles.ResizeHandleHoverStyle |
| 2491 | if m.isDragging { |
| 2492 | centerStyle = styles.ResizeHandleActiveStyle |
| 2493 | } |
| 2494 | |
| 2495 | // Show a small centered highlight when hovered or dragging |
| 2496 | centerPart := strings.Repeat("─", min(resizeHandleWidth, innerWidth)) |
| 2497 | handle := centerStyle.Render(centerPart) |
| 2498 | |
| 2499 | // Always center handle on full width |
| 2500 | fullLine := lipgloss.PlaceHorizontal( |
| 2501 | max(0, innerWidth), lipgloss.Center, handle, |
| 2502 | lipgloss.WithWhitespaceChars("─"), |
| 2503 | lipgloss.WithWhitespaceStyle(styles.ResizeHandleStyle), |
| 2504 | ) |
| 2505 | |
| 2506 | var result string |
| 2507 | switch { |
| 2508 | case m.sessionState.PauseState() == service.PausePaused: |
| 2509 | // Static indicator: the loop is idle until the user resumes. |
| 2510 | resumeKey := styles.HighlightWhiteStyle.Render("/pause") |
| 2511 | suffix := " " + styles.WarningStyle.Render("⏸ Paused") + " (" + resumeKey + " to resume)" |
| 2512 | suffixWidth := lipgloss.Width(suffix) |
| 2513 | result = lipgloss.NewStyle().MaxWidth(innerWidth-suffixWidth).Render(fullLine) + suffix |
| 2514 | |
| 2515 | case m.sessionState.PauseState() == service.PausePausing: |
| 2516 | // The agent is finishing the in-flight request before it pauses. |
| 2517 | suffix := " " + m.workingSpinner.View() + " " + styles.WarningStyle.Render("Pausing…") + " (finishing current request)" |
| 2518 | suffixWidth := lipgloss.Width(suffix) |
| 2519 | result = lipgloss.NewStyle().MaxWidth(innerWidth-suffixWidth).Render(fullLine) + suffix |
| 2520 | |
| 2521 | case m.chatPage.IsWorking(): |
| 2522 | // Truncate right side and append spinner (handle stays centered) |
| 2523 | workingText := "Working…" |
| 2524 | if queueLen := m.chatPage.QueueLength(); queueLen > 0 { |
| 2525 | workingText = fmt.Sprintf("Working… (%d queued)", queueLen) |
| 2526 | } |
| 2527 | suffix := " " + m.workingSpinner.View() + " " + styles.SpinnerDotsHighlightStyle.Render(workingText) |
| 2528 | cancelKeyPart := styles.HighlightWhiteStyle.Render("Esc") |
| 2529 | suffix += " (" + cancelKeyPart + " to interrupt)" |
| 2530 | suffixWidth := lipgloss.Width(suffix) |
| 2531 | result = lipgloss.NewStyle().MaxWidth(innerWidth-suffixWidth).Render(fullLine) + suffix |
| 2532 | |
| 2533 | case m.chatPage.QueueLength() > 0: |
| 2534 | queueText := fmt.Sprintf("%d queued", m.chatPage.QueueLength()) |
| 2535 | suffix := " " + styles.WarningStyle.Render(queueText) + " " |
| 2536 | suffixWidth := lipgloss.Width(suffix) |
| 2537 | result = lipgloss.NewStyle().MaxWidth(innerWidth-suffixWidth).Render(fullLine) + suffix |
| 2538 | |
| 2539 | default: |
no test coverage detected