From 77c85a2480f13c5f0362e4c3e75c3233409a5dfb Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 6 Mar 2023 15:19:18 +0100 Subject: [PATCH 1/2] Switching to table --- models/itemDelegate.go | 60 ----------------------------- models/organisationModel.go | 26 ++++++++----- models/repositoryModel.go | 76 ++++++++++++++++++++++--------------- models/styles.go | 27 +++++++------ 4 files changed, 75 insertions(+), 114 deletions(-) delete mode 100644 models/itemDelegate.go diff --git a/models/itemDelegate.go b/models/itemDelegate.go deleted file mode 100644 index f01405d..0000000 --- a/models/itemDelegate.go +++ /dev/null @@ -1,60 +0,0 @@ -package models - -import ( - "fmt" - "io" - - "github.com/admcpr/hub-bub/structs" - "github.com/charmbracelet/bubbles/list" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - -// TODO: Pull this out into it's own file -type itemDelegate struct{} - -func (d itemDelegate) Height() int { return 1 } -func (d itemDelegate) Spacing() int { return 1 } -func (d itemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil } -func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { - i, ok := listItem.(structs.ListItem) - if !ok { - return - } - - // str := fmt.Sprintf("%s > %s", i.Title(), i.Description()) - - statusNugget := lipgloss.NewStyle(). - Foreground(lipgloss.Color(white)). - Padding(0, 1) - - // statusBarStyle := lipgloss.NewStyle(). - // Foreground(lipgloss.AdaptiveColor{Light: "#343433", Dark: "#C1C6B2"}). - // Background(lipgloss.AdaptiveColor{Light: "#D9DCCF", Dark: "#353533"}) - - // statusStyle := lipgloss.NewStyle(). - // Inherit(statusBarStyle). - // Foreground(lipgloss.Color("#FFFDF5")). - // Background(lipgloss.Color("#FF5F87")). - // Padding(0, 1). - // MarginRight(1) - - encodingStyle := statusNugget.Copy(). - Background(lipgloss.Color(pink)). - Align(lipgloss.Right) - - // str := lipgloss.JoinHorizontal(lipgloss.Left, i.Title(), i.Description()) - - title := statusNugget.Render(i.Title()) - description := encodingStyle.Render(i.Description()) - - // fn := itemStyle.Render - // if index == m.Index() { - // fn = func(s string) string { - // return selectedItemStyle.Render("> " + s) - // } - // } - fn := lipgloss.JoinHorizontal - - fmt.Fprint(w, fn(lipgloss.Left, title, description)) -} diff --git a/models/organisationModel.go b/models/organisationModel.go index ad0c803..9535751 100644 --- a/models/organisationModel.go +++ b/models/organisationModel.go @@ -21,15 +21,19 @@ type OrganisationModel struct { repoList list.Model settingList list.Model + repoModel RepositoryModel - activeTab int loaded bool width int height int tabsHaveFocus bool } -func (m *OrganisationModel) initList() { +func (m *OrganisationModel) panelWidth() int { + return m.width / 2 +} + +func (m *OrganisationModel) init() { m.repoList = list.New( []list.Item{}, list.NewDefaultDelegate(), @@ -46,6 +50,7 @@ func (m *OrganisationModel) initList() { 0, 0, ) + m.repoModel = NewRepositoryModel(m.panelWidth(), m.height) } func (m OrganisationModel) Init() tea.Cmd { @@ -70,7 +75,7 @@ func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case messages.RepositoryListMsg: m.repoList = buildRepoListModel(msg.OrganizationQuery, m.width, m.height) m.RepoQuery = msg.OrganizationQuery - m.repositorySettingsTabs = structs.BuildRepositorySettings(m.RepoQuery.Organization.Repositories.Edges[m.repoList.Index()].Node) + m.repoModel.SelectRepo(m.getSelectedRepo()) return m, nil case tea.KeyMsg: @@ -81,16 +86,17 @@ func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.tabsHaveFocus = false return m, nil case tea.KeyRight: - m.activeTab = min(m.activeTab+1, len(m.repositorySettingsTabs)-1) + m.repoModel.NextTab() case tea.KeyLeft: - m.activeTab = max(m.activeTab-1, 0) + m.repoModel.PreviousTab() } } else { switch msg.Type { case tea.KeyDown, tea.KeyUp: - m.repositorySettingsTabs = structs.BuildRepositorySettings(m.RepoQuery.Organization.Repositories.Edges[m.repoList.Index()].Node) + m.repoModel.SelectRepo(m.getSelectedRepo()) case tea.KeyEnter: m.tabsHaveFocus = true + m.repoModel.SelectRepo(m.getSelectedRepo()) case tea.KeyEsc: return MainModel[UserModelName], nil } @@ -98,19 +104,18 @@ func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "ctrl+c", "q": return m, tea.Quit } - m.repoList.SetWidth(200) m.repoList, cmd = m.repoList.Update(msg) } } - m.buildSettingListModel(m.repositorySettingsTabs[m.activeTab], m.width, m.height) + // m.buildSettingListModel(m.repositorySettingsTabs[m.activeTab], m.width, m.height) return m, cmd } // View implements tea.Model func (m OrganisationModel) View() string { - var repoList = appStyle.Width(m.width / 2).Render(m.repoList.View()) + var repoList = appStyle.Width((m.width / 2) - 4).Render(m.repoList.View()) var settingList = lipgloss.JoinVertical(lipgloss.Left, m.Tabs(), settingsStyle.Width(m.width/2).Render(m.settingList.View())) var views = []string{repoList, settingList} @@ -193,7 +198,8 @@ func (m OrganisationModel) Tabs() string { } else if isLast && !isActive { border.BottomRight = "┤" } - style = style.Border(border).Width(m.width / 2 / len(Tabs)) + // TODO: Calculate width of tabs correctly so they match m.width + style = style.Border(border).Width((m.width / 2 / len(Tabs)) - 1) renderedTabs = append(renderedTabs, style.Render(t)) } diff --git a/models/repositoryModel.go b/models/repositoryModel.go index 2ad93a6..28ceb3a 100644 --- a/models/repositoryModel.go +++ b/models/repositoryModel.go @@ -1,9 +1,8 @@ package models import ( - "github.com/admcpr/hub-bub/messages" "github.com/admcpr/hub-bub/structs" - "github.com/charmbracelet/bubbles/list" + "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) @@ -11,30 +10,40 @@ import ( type RepositoryModel struct { repositorySettingsTabs []structs.RepositorySettingsTab - settingList list.Model + settingsTable table.Model - activeTab int - loaded bool - width int - height int - tabsHaveFocus bool + activeTab int + loaded bool + width int + height int } -func (m *RepositoryModel) initList() { - m.settingList = list.New( - []list.Item{}, - list.NewDefaultDelegate(), - // m.width, - // m.height, - 0, - 0, - ) +func NewRepositoryModel(width, height int) RepositoryModel { + return RepositoryModel{ + repositorySettingsTabs: []structs.RepositorySettingsTab{}, + width: width, + height: height, + } } func (m RepositoryModel) Init() tea.Cmd { return nil } +func (m *RepositoryModel) SelectRepo(RepositoryQuery structs.RepositoryQuery) { + m.repositorySettingsTabs = structs.BuildRepositorySettings(RepositoryQuery) + + m.buildSettingListModel(m.repositorySettingsTabs[m.activeTab], m.width, m.height) +} + +func (m *RepositoryModel) NextTab() { + m.activeTab = min(m.activeTab+1, len(m.repositorySettingsTabs)-1) +} + +func (m *RepositoryModel) PreviousTab() { + m.activeTab = max(m.activeTab-1, 0) +} + func (m RepositoryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd @@ -50,10 +59,14 @@ func (m RepositoryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } return m, nil - case messages.RepositoryListMsg: - // m.repositorySettingsTabs = structs.BuildRepositorySettings(m.RepoQuery.Organization.Repositories.Edges[m.repoList.Index()].Node) + case messages.RepoSelectedMsg: + m.repositorySettingsTabs = structs.BuildRepositorySettings(msg.RepositoryQuery) return m, nil + // case messages.RepoListMsg: + // // m.repositorySettingsTabs = structs.BuildRepositorySettings(m.RepoQuery.Organization.Repositories.Edges[m.repoList.Index()].Node) + // return m, nil + case tea.KeyMsg: switch msg.Type { case tea.KeyEsc: @@ -66,29 +79,31 @@ func (m RepositoryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } } - m.buildSettingListModel(m.repositorySettingsTabs[m.activeTab], m.width, m.height) - return m, cmd } func (m RepositoryModel) View() string { var tabs = m.RenderTabs() - var settings = settingsStyle.Render(m.settingList.View()) + var settings = settingsStyle.Render(m.settingsTable.View()) return lipgloss.JoinVertical(lipgloss.Left, tabs, settings) } func (m *RepositoryModel) buildSettingListModel(tabSettings structs.RepositorySettingsTab, width, height int) { - items := make([]list.Item, len(tabSettings.Settings)) + columns := []table.Column{{Title: "Name", Width: 30}, {Title: "Value", Width: 10}} + + rows := make([]table.Row, len(tabSettings.Settings)) for i, setting := range tabSettings.Settings { - items[i] = structs.NewListItem(setting.Name, setting.Value) + rows[i] = table.Row{setting.Name, setting.Value} } - m.settingList = list.New(items, itemDelegate{}, width, height-titleHeight-4) - m.settingList.Title = tabSettings.Name - m.settingList.SetShowHelp(false) - m.settingList.SetShowTitle(false) - m.settingList.SetShowStatusBar(false) + m.settingsTable = table.New( + table.WithColumns(columns), + table.WithRows(rows), + table.WithWidth(width), + table.WithHeight(20)) + // table.WithHeight(height-titleHeight-4)) + } func (m RepositoryModel) RenderTabs() string { @@ -117,7 +132,8 @@ func (m RepositoryModel) RenderTabs() string { } else if isLast && !isActive { border.BottomRight = "┤" } - style = style.Border(border) + // TODO: Calculate width of tabs correctly so they match m.width + style = style.Border(border) //.Width((m.width / len(Tabs)) - 1) renderedTabs = append(renderedTabs, style.Render(t)) } diff --git a/models/styles.go b/models/styles.go index dedaf0c..1009d2a 100644 --- a/models/styles.go +++ b/models/styles.go @@ -4,10 +4,10 @@ import "github.com/charmbracelet/lipgloss" var ( // Colors - purple = "#cdb4db" - pink = "#ffc8dd" - pinkDarker = "#ffafcc" - blue = "#bde0fe" + // purple = "#cdb4db" + // pink = "#ffc8dd" + // pinkDarker = "#ffafcc" + // blue = "#bde0fe" blueDarker = "#a2d2ff" white = "#FFFDF5" @@ -21,20 +21,19 @@ var ( titleHeight = 2 // Custom list - itemStyle = lipgloss.NewStyle(). - PaddingLeft(4) - selectedItemStyle = lipgloss.NewStyle(). - PaddingLeft(2). - Foreground(lipgloss.Color(blue)) + // itemStyle = lipgloss.NewStyle().PaddingLeft(4) + // selectedItemStyle = lipgloss.NewStyle(). + // PaddingLeft(2). + // Foreground(lipgloss.Color(blue)) // Tabs inactiveTabBorder = tabBorderWithBottom("┴", "─", "┴") activeTabBorder = tabBorderWithBottom("┘", " ", "└") - docStyle = lipgloss.NewStyle().Padding(1, 2, 1, 2) - highlightColor = lipgloss.Color(pinkDarker) - borderColor = lipgloss.Color(blueDarker) - inactiveTabStyle = lipgloss.NewStyle().Border(inactiveTabBorder, true).BorderForeground(borderColor).Padding(0, 1) - activeTabStyle = inactiveTabStyle.Copy().Border(activeTabBorder, true) + // docStyle = lipgloss.NewStyle().Padding(1, 2, 1, 2) + // highlightColor = lipgloss.Color(pinkDarker) + borderColor = lipgloss.Color(blueDarker) + inactiveTabStyle = lipgloss.NewStyle().Border(inactiveTabBorder, true).BorderForeground(borderColor).Padding(0, 1) + activeTabStyle = inactiveTabStyle.Copy().Border(activeTabBorder, true) settingsStyle = appStyle.Copy().Border(listSettingsBorder()). BorderForeground(borderColor).Padding(0, 1, 1, 1) From f6ec565c5cd4ebfc25db1a4a4992de779172acdb Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 6 Mar 2023 15:23:13 +0100 Subject: [PATCH 2/2] Switch to table --- models/organisationModel.go | 77 ++++++------------------------------- models/repositoryModel.go | 20 ---------- 2 files changed, 11 insertions(+), 86 deletions(-) diff --git a/models/organisationModel.go b/models/organisationModel.go index 9535751..7049bb7 100644 --- a/models/organisationModel.go +++ b/models/organisationModel.go @@ -17,11 +17,8 @@ type OrganisationModel struct { Url string RepoQuery structs.OrganizationQuery - repositorySettingsTabs []structs.RepositorySettingsTab - - repoList list.Model - settingList list.Model - repoModel RepositoryModel + repoList list.Model + repoModel RepositoryModel loaded bool width int @@ -33,6 +30,10 @@ func (m *OrganisationModel) panelWidth() int { return m.width / 2 } +func (m *OrganisationModel) getSelectedRepo() structs.RepositoryQuery { + return m.RepoQuery.Organization.Repositories.Edges[m.repoList.Index()].Node +} + func (m *OrganisationModel) init() { m.repoList = list.New( []list.Item{}, @@ -42,14 +43,7 @@ func (m *OrganisationModel) init() { 0, 0, ) - m.settingList = list.New( - []list.Item{}, - list.NewDefaultDelegate(), - // m.width, - // m.height, - 0, - 0, - ) + m.repoModel = NewRepositoryModel(m.panelWidth(), m.height) } @@ -67,7 +61,7 @@ func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.width = msg.Width if !m.loaded { - m.initList() + m.init() m.loaded = true } return m, nil @@ -116,9 +110,9 @@ func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // View implements tea.Model func (m OrganisationModel) View() string { var repoList = appStyle.Width((m.width / 2) - 4).Render(m.repoList.View()) - var settingList = lipgloss.JoinVertical(lipgloss.Left, m.Tabs(), settingsStyle.Width(m.width/2).Render(m.settingList.View())) - - var views = []string{repoList, settingList} + // var settingList = lipgloss.JoinVertical(lipgloss.Left, m.Tabs(), settingsStyle.Width(m.width/2).Render(m.settingList.View())) + var settings = appStyle.Width(m.width / 2).Render(m.repoModel.View()) + var views = []string{repoList, settings} return lipgloss.JoinHorizontal(lipgloss.Top, views...) } @@ -158,52 +152,3 @@ func buildRepoListModel(organizationQuery structs.OrganizationQuery, width, heig return list } - -func (m *OrganisationModel) buildSettingListModel(tabSettings structs.RepositorySettingsTab, width, height int) { - items := make([]list.Item, len(tabSettings.Settings)) - for i, setting := range tabSettings.Settings { - items[i] = structs.NewListItem(setting.Name, setting.Value) - } - - m.settingList = list.New(items, itemDelegate{}, width, height-titleHeight-4) - m.settingList.Title = tabSettings.Name - m.settingList.SetShowHelp(false) - m.settingList.SetShowTitle(false) - m.settingList.SetShowStatusBar(false) -} - -func (m OrganisationModel) Tabs() string { - Tabs := []string{} - for _, t := range m.repositorySettingsTabs { - Tabs = append(Tabs, t.Name) - } - - var renderedTabs []string - - for i, t := range Tabs { - var style lipgloss.Style - isFirst, isLast, isActive := i == 0, i == len(Tabs)-1, i == m.activeTab - if isActive { - style = activeTabStyle.Copy() - } else { - style = inactiveTabStyle.Copy() - } - border, _, _, _, _ := style.GetBorder() - if isFirst && isActive { - border.BottomLeft = "│" - } else if isFirst && !isActive { - border.BottomLeft = "├" - } else if isLast && isActive { - border.BottomRight = "│" - } else if isLast && !isActive { - border.BottomRight = "┤" - } - // TODO: Calculate width of tabs correctly so they match m.width - style = style.Border(border).Width((m.width / 2 / len(Tabs)) - 1) - renderedTabs = append(renderedTabs, style.Render(t)) - } - - row := lipgloss.JoinHorizontal(lipgloss.Top, renderedTabs...) - - return row -} diff --git a/models/repositoryModel.go b/models/repositoryModel.go index 28ceb3a..e057d04 100644 --- a/models/repositoryModel.go +++ b/models/repositoryModel.go @@ -54,29 +54,9 @@ func (m RepositoryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.width = msg.Width if !m.loaded { - m.initList() m.loaded = true } return m, nil - - case messages.RepoSelectedMsg: - m.repositorySettingsTabs = structs.BuildRepositorySettings(msg.RepositoryQuery) - return m, nil - - // case messages.RepoListMsg: - // // m.repositorySettingsTabs = structs.BuildRepositorySettings(m.RepoQuery.Organization.Repositories.Edges[m.repoList.Index()].Node) - // return m, nil - - case tea.KeyMsg: - switch msg.Type { - case tea.KeyEsc: - m.tabsHaveFocus = false - return m, nil - case tea.KeyRight: - m.activeTab = min(m.activeTab+1, len(m.repositorySettingsTabs)-1) - case tea.KeyLeft: - m.activeTab = max(m.activeTab-1, 0) - } } return m, cmd