From ecbb5225ef93ddda5e65680ada989d448bdad6df Mon Sep 17 00:00:00 2001 From: Cam Sweeney Date: Thu, 13 Jun 2024 20:57:19 -0700 Subject: [PATCH] better sizing --- ui/app.go | 41 +++++++++++------------------ ui/cast_details.go | 64 ++++++++++++++++++++++++++++++++++++---------- ui/feed.go | 62 +++++++++++++++++++++++--------------------- ui/profile.go | 9 ++++--- ui/sidebar.go | 14 ++++++---- ui/statusline.go | 9 ++++--- 6 files changed, 119 insertions(+), 80 deletions(-) diff --git a/ui/app.go b/ui/app.go index 316cd8a..682d9c2 100644 --- a/ui/app.go +++ b/ui/app.go @@ -16,6 +16,10 @@ import ( // TODO provide to models var renderer *lipgloss.Renderer = lipgloss.DefaultRenderer() +var ( + mainStyle = lipgloss.NewStyle().Margin(0).Padding(0).Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("#874BFD")) +) + func NewStyle() lipgloss.Style { return renderer.NewStyle() } @@ -140,7 +144,6 @@ func NewApp(cfg *config.Config, ctx *AppContext) *App { return a } - func (a *App) SetNavName(name string) { a.prevName = a.navname a.navname = name @@ -271,9 +274,9 @@ func (a *App) Update(msg tea.Msg) (tea.Model, tea.Cmd) { SetWidth(msg.Width) a.statusLine.SetSize(msg.Width, 1) + _, statusHeight := lipgloss.Size(a.statusLine.View()) - // set the height of the statusLine - wx, wy := msg.Width, msg.Height-1 + wx, wy := msg.Width, msg.Height-statusHeight sideMax := 30 sidePct := int(float64(wx) * 0.2) @@ -281,23 +284,19 @@ func (a *App) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if sideMax < sidePct { sx = sideMax } - a.sidebar.SetSize(sx, wy) + a.sidebar.SetSize(sx, wy-4) + sideWidth, _ := lipgloss.Size(a.sidebar.View()) - qw := wx - sx - qh := wy - 10 - a.quickSelect.SetSize(qw, qh) - - pw := wx - sx + pw := wx - sideWidth py := wy - 10 a.publish.SetSize(pw, py) a.splash.SetSize(pw, py) + a.quickSelect.SetSize(pw, py) + a.help.SetSize(pw, py) - hw := wx - sx - hy := wy - 10 - a.help.SetSize(hw, hy) + fx, fy := mainStyle.GetFrameSize() + mx, my := wx-sideWidth-fx-4, wy-fy - // substract the sidebar width from the window width - mx, my := wx-sx, wy childMsg := tea.WindowSizeMsg{ Width: mx, Height: my, @@ -394,21 +393,11 @@ func (a *App) View() string { main = a.help.View() } + main = mainStyle.Render(main) + return lipgloss.JoinVertical(lipgloss.Top, lipgloss.JoinHorizontal(lipgloss.Center, side, main), a.statusLine.View(), ) } - -func UpdateChildren(msg tea.Msg, models ...tea.Model) tea.Cmd { - cmds := make([]tea.Cmd, len(models)) - - // Only text inputs with Focus() set will respond, so it's safe to simply - // update all of them here without any further logic. - for i := range models { - models[i], cmds[i] = models[i].Update(msg) - } - - return tea.Batch(cmds...) -} diff --git a/ui/cast_details.go b/ui/cast_details.go index 4f2a8e5..9106352 100644 --- a/ui/cast_details.go +++ b/ui/cast_details.go @@ -10,7 +10,9 @@ import ( "github.com/treethought/tofui/api" ) -var style = NewStyle().Margin(2, 2).BorderStyle(lipgloss.RoundedBorder()).Border(lipgloss.RoundedBorder(), true) +var style = NewStyle() +var statsStyle = NewStyle() +var castHeaderStyle = NewStyle().Margin(1, 1).Align(lipgloss.Top) type CastView struct { app *App @@ -19,12 +21,17 @@ type CastView struct { pfp *ImageModel replies *RepliesView vp *viewport.Model + header *viewport.Model + hasImg bool pubReply *PublishInput + w, h int } func NewCastView(app *App, cast *api.Cast) *CastView { vp := viewport.New(0, 0) + hp := viewport.New(0, 0) + hp.Style = NewStyle().BorderBottom(true).BorderStyle(lipgloss.RoundedBorder()) c := &CastView{ app: app, cast: cast, @@ -32,7 +39,9 @@ func NewCastView(app *App, cast *api.Cast) *CastView { img: NewImage(true, true, special), replies: NewRepliesView(app), vp: &vp, + header: &hp, pubReply: NewPublishInput(app), + hasImg: false, } return c } @@ -55,7 +64,9 @@ func (m *CastView) SetCast(cast *api.Cast) tea.Cmd { m.pfp.SetSize(4, 4), m.pubReply.SetContext(m.cast.Hash, m.cast.ParentURL, m.cast.Author.FID), } + m.hasImg = false if len(m.cast.Embeds) > 0 { + m.hasImg = true cmds = append(cmds, m.img.SetURL(m.cast.Embeds[0].URL, true)) } return tea.Sequence(cmds...) @@ -65,6 +76,13 @@ func (m *CastView) Init() tea.Cmd { return nil } +func min(a, b int) int { + if a < b { + return a + } + return b +} + func (m *CastView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: @@ -72,16 +90,26 @@ func (m *CastView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { fx, fy := style.GetFrameSize() - w, h := msg.Width-fx, msg.Height-fy-6 // room for stats/header + w, h := msg.Width-fx, msg.Height-fy + m.w, m.h = w, h + + m.header.Width = w + m.header.Height = min(10, int(float64(h)*0.2)) - cx, cy := w, h/2 + hHeight := lipgloss.Height(m.header.View()) + + cx, cy := w, h-hHeight m.vp.Width = cx - m.vp.Height = cy / 2 + m.vp.Height = int(float64(cy) * 0.5) - m.img.SetSize(cx/2, cy/2) + m.img.SetSize(0, 0) - m.replies.SetSize(msg.Width, h/2) + if m.hasImg { + m.img.SetSize(4, 4) + m.vp.Height = int(float64(cy) * 0.25) + } + m.replies.SetSize(msg.Width, int(float64(cy)*0.5)) m.pubReply.SetSize(msg.Width, msg.Height-10) return m, tea.Batch(cmds...) @@ -108,15 +136,12 @@ func (m *CastView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } } m.vp.SetContent(CastContent(m.cast, 10)) + m.header.SetContent(m.castHeader()) cmds := []tea.Cmd{} _, rcmd := m.replies.Update(msg) cmds = append(cmds, rcmd) - // v, vcmd := m.vp.Update(msg) - // m.vp = &v - // cmds = append(cmds, vcmd) - if m.img.Matches(msg) { _, icmd := m.img.Update(msg) _, pcmd := m.pfp.Update(msg) @@ -126,16 +151,27 @@ func (m *CastView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Batch(cmds...) } +func (m *CastView) castHeader() string { + if m.cast == nil { + return "" + } + return castHeaderStyle.Render( + lipgloss.JoinVertical(lipgloss.Center, + UsernameHeader(&m.cast.Author, m.pfp), + CastStats(m.cast, 1), + ), + ) + +} + func (m *CastView) View() string { if m.pubReply.Active() { return m.pubReply.View() } - return style.Render( + return style.Height(m.h).Render( lipgloss.JoinVertical(lipgloss.Center, - UsernameHeader(&m.cast.Author, m.pfp), - NewStyle().BorderStyle(lipgloss.NormalBorder()).BorderBottom(true).Padding(0).Render(CastStats(m.cast, 10)), - // CastContent(m.cast, 10), + m.header.View(), m.vp.View(), m.img.View(), m.replies.View(), diff --git a/ui/feed.go b/ui/feed.go index 6668152..557ae2e 100644 --- a/ui/feed.go +++ b/ui/feed.go @@ -16,8 +16,8 @@ import ( ) var ( - docStyle = NewStyle().Margin(2, 2).Align(lipgloss.Center) - channelHeaderStyle = NewStyle().Margin(1, 1).Align(lipgloss.Center).Border(lipgloss.RoundedBorder()) + feedStyle = NewStyle().Margin(2, 2).Align(lipgloss.Center) + channelHeaderStyle = NewStyle().Margin(1, 1).Align(lipgloss.Top).Border(lipgloss.RoundedBorder()) ) type feedType string @@ -141,8 +141,8 @@ func (m *FeedView) SetShowStats(show bool) { } func (m *FeedView) setTableConfig() { - fw, _ := docStyle.GetFrameSize() - w := m.table.Width() - fw + fx, _ := feedStyle.GetFrameSize() + w := m.table.Width() - fx //- 10 if !m.showChannel && !m.showStats { m.table.SetColumns([]table.Column{ @@ -155,7 +155,7 @@ func (m *FeedView) setTableConfig() { {Title: "channel", Width: int(float64(w) * 0.2)}, {Title: "", Width: int(float64(w) * 0.1)}, {Title: "user", Width: int(float64(w) * 0.2)}, - {Title: "cast", Width: int(float64(w) * 0.5)}, + {Title: "cast", Width: int(float64(w)*0.5) - 4}, }) return @@ -301,31 +301,36 @@ func (m *FeedView) getCurrentItem() *CastFeedItem { } return m.items[row] } -func (m *FeedView) SetSize(w, h int) { - m.w, m.h = w, h - docStyle = docStyle.MaxWidth(w).MaxHeight(h) - dsx, dsy := docStyle.GetFrameSize() - tstyle := getTableStyles().Selected - tsx, tsy := tstyle.GetFrameSize() - x, y := dsx+tsx, dsy+tsy - - m.headerImg.SetSize(4, 4) - m.table.SetWidth(w - x) - - hh := h - y +func (m *FeedView) hideDescription() { m.descVp.Width = 0 m.descVp.Height = 0 - m.descVp.Style = NewStyle() + m.headerImg.SetSize(0, 0) + +} + +func (m *FeedView) SetSize(w, h int) { + m.w, m.h = w, h + + m.hideDescription() if m.description != "" { - m.descVp.Width = w - x - m.descVp.Height = 4 - m.descVp.Style = channelHeaderStyle - dy := lipgloss.Height(m.descVp.View()) - hh = hh - dy - 5 + m.descVp.SetContent(m.description) + dmin := 8 + dPct := int(float64(h) * 0.2) + dy := dPct + if dmin > dPct { + dy = dmin + } + m.headerImg.SetSize(4, 4) + fx, fy := channelHeaderStyle.GetFrameSize() + m.descVp.Width = w - fx - 4 + m.descVp.Height = dy - fy } - m.table.SetHeight(hh) + _, dy := lipgloss.Size(channelHeaderStyle.Render(m.descVp.View())) + fx, fy := feedStyle.GetFrameSize() + m.table.SetWidth(w - fx) + m.table.SetHeight(h - fy - dy ) m.setTableConfig() lw := int(float64(w) * 0.2) @@ -416,7 +421,6 @@ func (m *FeedView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, cmd case *api.FeedResponse: - m.Clear() return m, m.setItems(msg.Casts) case *channelFeedMsg: if msg.err != nil { @@ -490,12 +494,12 @@ func (m *FeedView) View() string { } if m.feedType == feedTypeChannel { return lipgloss.JoinVertical(lipgloss.Top, - docStyle.Render(m.descVp.View()), - docStyle.Render(m.table.View()), + channelHeaderStyle.Render(m.descVp.View()), + feedStyle.Render(m.table.View()), ) } - return docStyle.Render(m.table.View()) + return feedStyle.Render(m.table.View()) } @@ -528,6 +532,6 @@ func channelHeader(c *api.Channel, img *ImageModel) string { func channelDescription(c *api.Channel, img *ImageModel) string { return lipgloss.JoinVertical(lipgloss.Bottom, channelHeader(c, img), - NewStyle().BorderStyle(lipgloss.NormalBorder()).BorderBottom(true).Padding(0).Render(channelStats(c, 10)), + NewStyle().BorderStyle(lipgloss.NormalBorder()).BorderBottom(true).Padding(0).Render(channelStats(c, 1)), ) } diff --git a/ui/profile.go b/ui/profile.go index 6ac3377..5ec07c9 100644 --- a/ui/profile.go +++ b/ui/profile.go @@ -107,10 +107,13 @@ func (m *Profile) Update(msg tea.Msg) (tea.Model, tea.Cmd) { x, y := msg.Width, msg.Height m.pfp.SetSize(4, 4) + hy := lipgloss.Height(UsernameHeader(m.user, m.pfp)) + by := lipgloss.Height(UserBio(m.user)) + + fy := y - hy - by + // TODO use size of header/stats - fx := x - fy := int(float64(y) * 0.6) - m.feed.SetSize(fx, fy) + m.feed.SetSize(x, fy) return m, nil case *SelectProfileMsg: diff --git a/ui/sidebar.go b/ui/sidebar.go index c880b5f..56bda3c 100644 --- a/ui/sidebar.go +++ b/ui/sidebar.go @@ -59,7 +59,7 @@ func (i *sidebarItem) Description() string { return "" } -var navStyle = NewStyle().Margin(2, 2, 0, 2).BorderRight(true).BorderStyle(lipgloss.RoundedBorder()) +var navStyle = NewStyle().Margin(2, 2, 0, 0).BorderRight(true).BorderStyle(lipgloss.RoundedBorder()) func NewSidebar(app *App) *Sidebar { d := list.NewDefaultDelegate() @@ -84,10 +84,10 @@ func NewSidebar(app *App) *Sidebar { func (m *Sidebar) SetSize(w, h int) { x, y := navStyle.GetFrameSize() - m.nav.SetWidth(w - x) - m.nav.SetHeight(h - y - 4) + m.w, m.h = w-x, h-y + m.nav.SetWidth(m.w) + m.nav.SetHeight(m.h) m.pfp.SetSize(4, 4) - m.w, m.h = w, h } func (m *Sidebar) Active() bool { @@ -149,7 +149,11 @@ func (m *Sidebar) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if fid == 0 { return m, nil } - return m, tea.Sequence(m.app.FocusProfile(), selectProfileCmd(fid)) + return m, tea.Sequence( + m.app.FocusProfile(), + getUserCmd(m.app.client, fid, m.app.ctx.signer.FID), + getUserFeedCmd(m.app.client, fid, m.app.ctx.signer.FID), + ) } if currentItem.name == "feed" { m.SetActive(false) diff --git a/ui/statusline.go b/ui/statusline.go index 015a4bd..efe6ff1 100644 --- a/ui/statusline.go +++ b/ui/statusline.go @@ -6,6 +6,8 @@ import ( "github.com/mistakenelf/teacup/statusbar" ) +var statusStyle = NewStyle().BorderTop(true).BorderStyle(lipgloss.RoundedBorder()) + type StatusLine struct { app *App sb statusbar.Model @@ -41,8 +43,9 @@ func NewStatusLine(app *App) *StatusLine { } func (m *StatusLine) SetSize(width, height int) { - m.sb.SetSize(width) - m.sb.Height = 1 + fx, _ := statusStyle.GetFrameSize() + m.sb.SetSize(width - fx) + m.sb.Height = 1 } func (m *StatusLine) Init() tea.Cmd { @@ -56,5 +59,5 @@ func (m *StatusLine) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m *StatusLine) View() string { - return m.sb.View() + return statusStyle.Render(m.sb.View()) }