Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 27, 2025

Adds mouse click support to the TUI grid so clicking a goal opens its details view (same as keyboard navigation with Enter).

Changes

  • Enable mouse events (main.go): Added tea.WithMouseCellMotion() to program initialization
  • Handle mouse messages (main.go): Added tea.MouseMsg case in updateApp, triggering on left button release when no modal is open
  • Click-to-goal mapping (handlers.go): New handleMouseClick function converts screen coordinates to goal index accounting for:
    • 2-line header offset
    • 4-line cell height
    • Current scroll position
    • Grid column layout based on terminal width
// Mouse click opens modal same as Enter key
case tea.MouseMsg:
    if !m.appModel.showModal && !m.appModel.showCreateModal {
        if msg.Action == tea.MouseActionRelease && msg.Button == tea.MouseButtonLeft {
            return handleMouseClick(m, msg)
        }
    }

Tests cover click positioning across rows/columns, scroll offsets, empty space handling, and modal state guards.

Original prompt

This section details on the original issue you should resolve

<issue_title>Make TUI clickable</issue_title>
<issue_description>## Objective

Make the TUI grid clickable so that when a user clicks a goal in the grid, it takes them to the goal's details view (same behavior as keyboard navigation).

Implementation Plan

1. Enable Mouse Support in Bubble Tea

In main.go, modify the program initialization to enable mouse events:

// Change from:
p := tea.NewProgram(initialModel(), tea.WithAltScreen())

// To:
p := tea.NewProgram(initialModel(), tea.WithAltScreen(), tea.WithMouseCellMotion())

The tea.WithMouseCellMotion() option enables mouse click and drag events.

2. Handle Mouse Events in the Update Function

In main.go, add a new case in the updateApp function to handle mouse clicks:

func (m model) updateApp(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	
	// Add this new case after the existing cases
	case tea.MouseMsg:
		// Only handle clicks when not in a modal
		if !m.appModel.showModal && !m.appModel.showCreateModal {
			if msg.Type == tea.MouseLeft {
				return handleMouseClick(m, msg)
			}
		}
		return m, nil
	
	// ... rest of existing cases
}

3. Implement the Mouse Click Handler

Add a new function in handlers.go to calculate which goal was clicked and navigate to it:

// handleMouseClick handles mouse click events on the grid
func handleMouseClick(m model, msg tea.MouseMsg) (tea.Model, tea.Cmd) {
	displayGoals := m.appModel.getDisplayGoals()
	if len(displayGoals) == 0 {
		return m, nil
	}

	// Calculate which goal was clicked based on coordinates
	// Header is ~2 lines, so content starts around line 2
	headerHeight := 2
	clickRow := msg.Y - headerHeight
	
	// Each grid cell is roughly 4 lines high (3 lines content + 1 spacing)
	cellHeight := 4
	gridRow := clickRow / cellHeight
	
	// Calculate column based on terminal width
	cols := calculateColumns(m.appModel.width)
	// Approximate cell width
	cellWidth := m.appModel.width / cols
	gridCol := msg.X / cellWidth
	
	// Calculate the goal index
	goalIndex := (m.appModel.scrollRow + gridRow) * cols + gridCol
	
	// Validate the index is within bounds
	if goalIndex >= 0 && goalIndex < len(displayGoals) {
		// Update cursor to clicked goal
		m.appModel.cursor = goalIndex
		m.appModel.hasNavigated = true
		m.appModel.lastNavigationTime = time.Now()
		
		// Open the modal immediately (same as pressing Enter)
		m.appModel.showModal = true
		m.appModel.modalGoal = &displayGoals[goalIndex]
		
		// Update cursor to point to goal in original list (for left/right navigation)
		for i, goal := range m.appModel.goals {
			if goal.Slug == displayGoals[goalIndex].Slug {
				m.appModel.cursor = i
				break
			}
		}
		
		// Load detailed goal information
		return m, tea.Batch(
			loadGoalDetailsCmd(m.appModel.config, m.appModel.modalGoal.Slug),
			navigationTimeoutCmd(navigationTimeout),
		)
	}
	
	return m, nil
}

How It Works

  1. Mouse Support: The tea.WithMouseCellMotion() option tells Bubble Tea to send mouse events to the Update function
  2. Click Detection: When a left-click occurs, the handler receives the X/Y coordinates
  3. Grid Calculation: The handler converts pixel coordinates to grid row/column, accounting for:
    • Header height at the top
    • Cell dimensions (height and width)
    • Current scroll position
  4. Goal Selection: Once the goal index is calculated, it updates the cursor and opens the modal, just like pressing Enter
  5. Validation: The code checks bounds to ensure clicks on empty space or outside the grid are ignored

The implementation reuses the existing modal opening logic, so the behavior will be identical to keyboard navigation.
</issue_description>

Comments on the Issue (you are @copilot in this section)

@narthur @coderabbitai How would we go about adding this feature? @narthur @coderabbitai Please update this issue's description with our implementation plan.

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI self-assigned this Nov 27, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 27, 2025

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI changed the title [WIP] Make TUI grid clickable for user navigation feat: make TUI grid clickable Nov 27, 2025
Copilot AI requested a review from narthur November 27, 2025 18:55
@narthur narthur marked this pull request as ready for review December 2, 2025 14:08
Copilot AI review requested due to automatic review settings December 2, 2025 14:08
@cursor
Copy link

cursor bot commented Dec 2, 2025

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on January 30.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@github-actions
Copy link

github-actions bot commented Dec 2, 2025

🚀 Pre-release Build Ready

Test builds are ready! Install directly using the bin command:

# Install the pre-release
bin install https://github.com/PinePeakDigital/buzz/releases/tag/pr-180-latest buzz-pr-180
# Run the pre-release
buzz-pr-180
# Uninstall the pre-release
bin remove buzz-pr-180

Direct Download Links

Or download binaries directly from the pre-release page:

💡 No GitHub login required for downloads!

🗑️ This pre-release will be automatically deleted when the PR is closed.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds mouse click support to the TUI grid, allowing users to click on goals to open their details view - providing the same functionality as keyboard navigation with Enter.

Key Changes:

  • Mouse event support is now enabled in the TUI
  • Click-to-goal coordinate mapping accounts for grid layout, scroll position, and terminal dimensions
  • Comprehensive test coverage ensures correct click handling across various scenarios

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
main.go Enables mouse cell motion events and adds mouse message handler in updateApp that triggers on left button release when no modal is open
handlers.go Implements handleMouseClick function that converts screen coordinates to goal indices, accounting for header offset, cell dimensions, column layout, and scroll position
handlers_test.go Adds comprehensive tests for mouse click functionality including edge cases (empty space, header clicks, scroll offsets, modal state guards, button/action filtering)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make TUI clickable

2 participants