Diff
1diff --git a/ui/components/footer/footer.go b/ui/components/footer/footer.go
2index e0f8c0e262f8cbee167a6c0e93e9d3e447d3fdbd..4bce3cd8fc62fbd71ede4518515cb162f2928bae 100644
3--- a/ui/components/footer/footer.go
4+++ b/ui/components/footer/footer.go
5@@ -59,7 +59,10 @@ func (f *Footer) View() string {
6 s := f.common.Styles.Footer.Copy().
7 Width(f.common.Width)
8 helpView := f.help.View(f.keymap)
9- return s.Render(helpView)
10+ return f.common.Zone.Mark(
11+ "footer",
12+ s.Render(helpView),
13+ )
14 }
15
16 // ShortHelp returns the short help key bindings.
17diff --git a/ui/components/statusbar/statusbar.go b/ui/components/statusbar/statusbar.go
18index 92b27914b6ce77d278e0f242c7ffb2e1cd590a80..7b960569faf23f4668c2bfc3ddc3792cf73c9ad7 100644
19--- a/ui/components/statusbar/statusbar.go
20+++ b/ui/components/statusbar/statusbar.go
21@@ -59,7 +59,10 @@ func (s *StatusBar) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
22 func (s *StatusBar) View() string {
23 st := s.common.Styles
24 w := lipgloss.Width
25- help := st.StatusBarHelp.Render("? Help")
26+ help := s.common.Zone.Mark(
27+ "repo-help",
28+ st.StatusBarHelp.Render("? Help"),
29+ )
30 key := st.StatusBarKey.Render(s.msg.Key)
31 info := ""
32 if s.msg.Info != "" {
33diff --git a/ui/pages/repo/repo.go b/ui/pages/repo/repo.go
34index 170289c27e34c7d0fddb59e2aae23b3a950f2a0d..6469fe6d4f79043a1f4298444195f93634e2d237 100644
35--- a/ui/pages/repo/repo.go
36+++ b/ui/pages/repo/repo.go
37@@ -2,6 +2,7 @@ package repo
38
39 import (
40 "fmt"
41+ "time"
42
43 "github.com/charmbracelet/bubbles/help"
44 "github.com/charmbracelet/bubbles/key"
45@@ -44,6 +45,12 @@ func (t tab) String() string {
46 }[t]
47 }
48
49+// CopyUrlMsg is a message to copy the URL of the current repository.
50+type CopyUrlMsg struct{}
51+
52+// ResetUrlMsg is a message to reset the URL string.
53+type ResetUrlMsg struct{}
54+
55 // UpdateStatusBarMsg updates the status bar.
56 type UpdateStatusBarMsg struct{}
57
58@@ -63,6 +70,7 @@ type Repo struct {
59 statusbar *statusbar.StatusBar
60 panes []common.Component
61 ref *ggit.Reference
62+ copyUrl time.Time
63 }
64
65 // New returns a new Repo.
66@@ -190,7 +198,22 @@ func (r *Repo) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
67 }
68 if r.selectedRepo != nil {
69 cmds = append(cmds, r.updateStatusBarCmd)
70+ switch msg := msg.(type) {
71+ case tea.MouseMsg:
72+ if msg.Type == tea.MouseLeft {
73+ id := fmt.Sprintf("%s-url", r.selectedRepo.Repo())
74+ if r.common.Zone.Get(id).InBounds(msg) {
75+ cmds = append(cmds, r.copyUrlCmd())
76+ }
77+ }
78+ }
79 }
80+ case CopyUrlMsg:
81+ r.common.Copy.Copy(
82+ git.RepoURL(r.cfg.Host, r.cfg.Port, r.selectedRepo.Repo()),
83+ )
84+ case ResetUrlMsg:
85+ r.copyUrl = time.Time{}
86 case ReadmeMsg:
87 case FileItemsMsg:
88 f, cmd := r.panes[filesTab].Update(msg)
89@@ -285,8 +308,14 @@ func (r *Repo) headerView() string {
90 Width(r.common.Width - lipgloss.Width(desc) - 1).
91 Align(lipgloss.Right)
92 url := git.RepoURL(cfg.Host, cfg.Port, r.selectedRepo.Repo())
93+ if !r.copyUrl.IsZero() && r.copyUrl.Add(time.Second).After(time.Now()) {
94+ url = "copied!"
95+ }
96 url = common.TruncateString(url, r.common.Width-lipgloss.Width(desc)-1)
97- url = urlStyle.Render(url)
98+ url = r.common.Zone.Mark(
99+ fmt.Sprintf("%s-url", r.selectedRepo.Repo()),
100+ urlStyle.Render(url),
101+ )
102 style := r.common.Styles.Repo.Header.Copy().Width(r.common.Width)
103 return style.Render(
104 lipgloss.JoinVertical(lipgloss.Top,
105@@ -340,6 +369,18 @@ func (r *Repo) updateModels(msg tea.Msg) tea.Cmd {
106 return tea.Batch(cmds...)
107 }
108
109+func (r *Repo) copyUrlCmd() tea.Cmd {
110+ r.copyUrl = time.Now()
111+ return tea.Batch(
112+ func() tea.Msg {
113+ return CopyUrlMsg{}
114+ },
115+ tea.Tick(time.Second, func(time.Time) tea.Msg {
116+ return ResetUrlMsg{}
117+ }),
118+ )
119+}
120+
121 func updateStatusBarCmd() tea.Msg {
122 return UpdateStatusBarMsg{}
123 }
124diff --git a/ui/ui.go b/ui/ui.go
125index 43ed760d82db723a7d3f6503774e91e3cd36a624..79e77b0b5df2ccfea6549f3cabb90562bf0dd402 100644
126--- a/ui/ui.go
127+++ b/ui/ui.go
128@@ -194,6 +194,14 @@ func (ui *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
129 // Always show the footer on selection page.
130 ui.showFooter = true
131 }
132+ case tea.MouseMsg:
133+ if msg.Type == tea.MouseLeft {
134+ switch {
135+ case ui.common.Zone.Get("repo-help").InBounds(msg),
136+ ui.common.Zone.Get("footer").InBounds(msg):
137+ cmds = append(cmds, footer.ToggleFooterCmd)
138+ }
139+ }
140 }
141 case footer.ToggleFooterMsg:
142 ui.footer.SetShowAll(!ui.footer.ShowAll())