feat(ui): more mouse support

Ayman Bagabas created

Change summary

ui/components/footer/footer.go       |  5 ++
ui/components/statusbar/statusbar.go |  5 ++
ui/pages/repo/repo.go                | 43 +++++++++++++++++++++++++++++
ui/ui.go                             |  8 +++++
4 files changed, 58 insertions(+), 3 deletions(-)

Detailed changes

ui/components/footer/footer.go 🔗

@@ -59,7 +59,10 @@ func (f *Footer) View() string {
 	s := f.common.Styles.Footer.Copy().
 		Width(f.common.Width)
 	helpView := f.help.View(f.keymap)
-	return s.Render(helpView)
+	return f.common.Zone.Mark(
+		"footer",
+		s.Render(helpView),
+	)
 }
 
 // ShortHelp returns the short help key bindings.

ui/components/statusbar/statusbar.go 🔗

@@ -59,7 +59,10 @@ func (s *StatusBar) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 func (s *StatusBar) View() string {
 	st := s.common.Styles
 	w := lipgloss.Width
-	help := st.StatusBarHelp.Render("? Help")
+	help := s.common.Zone.Mark(
+		"repo-help",
+		st.StatusBarHelp.Render("? Help"),
+	)
 	key := st.StatusBarKey.Render(s.msg.Key)
 	info := ""
 	if s.msg.Info != "" {

ui/pages/repo/repo.go 🔗

@@ -2,6 +2,7 @@ package repo
 
 import (
 	"fmt"
+	"time"
 
 	"github.com/charmbracelet/bubbles/help"
 	"github.com/charmbracelet/bubbles/key"
@@ -44,6 +45,12 @@ func (t tab) String() string {
 	}[t]
 }
 
+// CopyUrlMsg is a message to copy the URL of the current repository.
+type CopyUrlMsg struct{}
+
+// ResetUrlMsg is a message to reset the URL string.
+type ResetUrlMsg struct{}
+
 // UpdateStatusBarMsg updates the status bar.
 type UpdateStatusBarMsg struct{}
 
@@ -63,6 +70,7 @@ type Repo struct {
 	statusbar    *statusbar.StatusBar
 	panes        []common.Component
 	ref          *ggit.Reference
+	copyUrl      time.Time
 }
 
 // New returns a new Repo.
@@ -190,7 +198,22 @@ func (r *Repo) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		}
 		if r.selectedRepo != nil {
 			cmds = append(cmds, r.updateStatusBarCmd)
+			switch msg := msg.(type) {
+			case tea.MouseMsg:
+				if msg.Type == tea.MouseLeft {
+					id := fmt.Sprintf("%s-url", r.selectedRepo.Repo())
+					if r.common.Zone.Get(id).InBounds(msg) {
+						cmds = append(cmds, r.copyUrlCmd())
+					}
+				}
+			}
 		}
+	case CopyUrlMsg:
+		r.common.Copy.Copy(
+			git.RepoURL(r.cfg.Host, r.cfg.Port, r.selectedRepo.Repo()),
+		)
+	case ResetUrlMsg:
+		r.copyUrl = time.Time{}
 	case ReadmeMsg:
 	case FileItemsMsg:
 		f, cmd := r.panes[filesTab].Update(msg)
@@ -285,8 +308,14 @@ func (r *Repo) headerView() string {
 		Width(r.common.Width - lipgloss.Width(desc) - 1).
 		Align(lipgloss.Right)
 	url := git.RepoURL(cfg.Host, cfg.Port, r.selectedRepo.Repo())
+	if !r.copyUrl.IsZero() && r.copyUrl.Add(time.Second).After(time.Now()) {
+		url = "copied!"
+	}
 	url = common.TruncateString(url, r.common.Width-lipgloss.Width(desc)-1)
-	url = urlStyle.Render(url)
+	url = r.common.Zone.Mark(
+		fmt.Sprintf("%s-url", r.selectedRepo.Repo()),
+		urlStyle.Render(url),
+	)
 	style := r.common.Styles.Repo.Header.Copy().Width(r.common.Width)
 	return style.Render(
 		lipgloss.JoinVertical(lipgloss.Top,
@@ -340,6 +369,18 @@ func (r *Repo) updateModels(msg tea.Msg) tea.Cmd {
 	return tea.Batch(cmds...)
 }
 
+func (r *Repo) copyUrlCmd() tea.Cmd {
+	r.copyUrl = time.Now()
+	return tea.Batch(
+		func() tea.Msg {
+			return CopyUrlMsg{}
+		},
+		tea.Tick(time.Second, func(time.Time) tea.Msg {
+			return ResetUrlMsg{}
+		}),
+	)
+}
+
 func updateStatusBarCmd() tea.Msg {
 	return UpdateStatusBarMsg{}
 }

ui/ui.go 🔗

@@ -194,6 +194,14 @@ func (ui *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 				// Always show the footer on selection page.
 				ui.showFooter = true
 			}
+		case tea.MouseMsg:
+			if msg.Type == tea.MouseLeft {
+				switch {
+				case ui.common.Zone.Get("repo-help").InBounds(msg),
+					ui.common.Zone.Get("footer").InBounds(msg):
+					cmds = append(cmds, footer.ToggleFooterCmd)
+				}
+			}
 		}
 	case footer.ToggleFooterMsg:
 		ui.footer.SetShowAll(!ui.footer.ShowAll())