Skip to content

Commit

Permalink
feat: improve ui
Browse files Browse the repository at this point in the history
Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com>
  • Loading branch information
caarlos0 committed Apr 11, 2023
1 parent b955e2d commit c4df6dd
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 28 deletions.
2 changes: 1 addition & 1 deletion cmd/clone-org/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func main() {
}

p := tea.NewProgram(ui.NewInitialModel(token, org, destination, isTUI), opts...)
if err := p.Start(); err != nil {
if _, err := p.Run(); err != nil {
return cli.NewExitError(err.Error(), 1)
}
return nil
Expand Down
58 changes: 46 additions & 12 deletions internal/ui/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,56 @@ import (
"fmt"

cloneorg "github.com/caarlos0/clone-org"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)

func newCloneModel(repos []cloneorg.Repo, org, destination string, tui bool) tea.Model {
func newCloneModel(repos []cloneorg.Repo, org, destination string, tui bool, w, h int) tea.Model {
var models []repoModel
for _, r := range repos {
models = append(models, newRepoView(r, destination))
}
return cloneModel{

m := cloneModel{
repos: models,
org: org,
destination: destination,
tui: tui,
}
margin := lipgloss.Height(footer) + lipgloss.Height(header(m))
vp := viewport.New(w, h-margin)
vp.YPosition = 1
m.viewport = vp
return m
}

// ListModel is the UI in which the user can select which forks should be
// deleted if any, and see details on each of them.
type cloneModel struct {
repos []repoModel
viewport viewport.Model
org string
destination string
done bool
tui bool
}

func (m cloneModel) Init() tea.Cmd {
var inits []tea.Cmd
inits := []tea.Cmd{m.viewport.Init()}
for _, r := range m.repos {
inits = append(inits, r.Init())
}
return tea.Batch(inits...)
}

func (m cloneModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
var cmds []tea.Cmd
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.viewport.Height = msg.Height - 2
m.viewport.Width = msg.Width
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q", "esc":
Expand All @@ -52,34 +66,54 @@ func (m cloneModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
return m, nil
}
var cmds []tea.Cmd
var cmd tea.Cmd
m.done = true

for i := range m.repos {
m.repos[i], cmd = m.repos[i].Update(msg)
cmds = append(cmds, cmd)
if m.repos[i].cloning {
m.done = false
}
}

var content string
for _, r := range m.repos {
if !r.cloning {
continue
}
content += "\n" + r.View()
}
for _, r := range m.repos {
if r.cloning {
continue
}
content += "\n" + r.View()
}
m.viewport.SetContent(content)

m.viewport, cmd = m.viewport.Update(msg)
cmds = append(cmds, cmd)

return m, tea.Batch(cmds...)
}

func (m cloneModel) View() string {
return header(m) + "\n" + m.viewport.View() + "\n" + footer
}

var footer = singleOptionHelp("q/esc", "quit")

func header(m cloneModel) string {
verb := "Cloning"
if m.done {
verb = "Cloned"
}
s := secondaryForeground.Render(fmt.Sprintf(
"%s %d repositories from %s to %s ...\n",

return secondaryForeground.Render(fmt.Sprintf(
"%s %d repositories from %s to %s ...",
verb,
len(m.repos),
m.org,
m.destination,
))
for _, r := range m.repos {
s += "\n" + r.View()
}

return s + "\n" + singleOptionHelp("q/esc", "quit")
}
21 changes: 13 additions & 8 deletions internal/ui/initial.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ func NewInitialModel(token, org, destination string, tui bool) tea.Model {

// InitialModel is the UI when the CLI starts, basically loading the repos.
type initialModel struct {
err error
spinner spinner.Model
token string
org string
destination string
loading bool
tui bool
err error
spinner spinner.Model
token string
org string
destination string
loading bool
tui bool
width, height int
}

func (m initialModel) Init() tea.Cmd {
Expand All @@ -40,12 +41,16 @@ func (m initialModel) Init() tea.Cmd {

func (m initialModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.height = msg.Height
m.width = msg.Width
return m, nil
case errMsg:
m.loading = false
m.err = msg.error
return m, nil
case gotRepoListMsg:
list := newCloneModel(msg.repos, m.org, m.destination, m.tui)
list := newCloneModel(msg.repos, m.org, m.destination, m.tui, m.width, m.height)
return list, list.Init()
case tea.KeyMsg:
switch msg.String() {
Expand Down
13 changes: 6 additions & 7 deletions internal/ui/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func newRepoView(repo cloneorg.Repo, destination string) repoModel {
s := spinner.NewModel()
s := spinner.New()
s.Spinner = spinner.Points
return repoModel{
repo: repo,
Expand All @@ -29,7 +29,7 @@ type repoModel struct {
}

func (m repoModel) Init() tea.Cmd {
return tea.Batch(cloneRepoCmd(m.repo, m.destination), spinner.Tick)
return tea.Batch(cloneRepoCmd(m.repo, m.destination), m.spinner.Tick)
}

func (m repoModel) Update(msg tea.Msg) (repoModel, tea.Cmd) {
Expand All @@ -50,12 +50,11 @@ func (m repoModel) Update(msg tea.Msg) (repoModel, tea.Cmd) {
case "ctrl+c", "q", "esc":
return m, tea.Quit
}
default:
var cmd tea.Cmd
m.spinner, cmd = m.spinner.Update(msg)
return m, cmd
}
return m, nil

var cmd tea.Cmd
m.spinner, cmd = m.spinner.Update(msg)
return m, cmd
}

func (m repoModel) View() string {
Expand Down

0 comments on commit c4df6dd

Please sign in to comment.