tui: add a "scroll bar" and error view
This commit is contained in:
parent
387dd7534c
commit
000a2ec6f2
@ -29,6 +29,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type model struct {
|
type model struct {
|
||||||
|
width int
|
||||||
|
height int
|
||||||
|
|
||||||
ctx *lmcli.Context
|
ctx *lmcli.Context
|
||||||
convShortname string
|
convShortname string
|
||||||
|
|
||||||
@ -135,8 +138,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case tea.WindowSizeMsg:
|
case tea.WindowSizeMsg:
|
||||||
|
m.width = msg.Width
|
||||||
|
m.height = msg.Height
|
||||||
m.content.Width = msg.Width
|
m.content.Width = msg.Width
|
||||||
m.content.Height = msg.Height - m.input.Height() - lipgloss.Height(m.footerView()) - lipgloss.Height(m.headerView())
|
m.content.Height = msg.Height - m.getFixedComponentHeight()
|
||||||
m.input.SetWidth(msg.Width-1)
|
m.input.SetWidth(msg.Width-1)
|
||||||
m.updateContent()
|
m.updateContent()
|
||||||
case msgConversationLoaded:
|
case msgConversationLoaded:
|
||||||
@ -202,6 +207,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
cmds = append(cmds, wrapError(err))
|
cmds = append(cmds, wrapError(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case msgError:
|
||||||
|
m.err = error(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cmds) > 0 {
|
if len(cmds) > 0 {
|
||||||
@ -229,15 +236,45 @@ func (m model) View() string {
|
|||||||
// without this, the below view functions may do weird things
|
// without this, the below view functions may do weird things
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.content.Height = m.height - m.getFixedComponentHeight()
|
||||||
|
|
||||||
|
sections := make([]string, 0, 6)
|
||||||
|
error := m.errorView()
|
||||||
|
scrollbar := m.scrollbarView()
|
||||||
|
sections = append(sections, m.headerView())
|
||||||
|
if scrollbar != "" {
|
||||||
|
sections = append(sections, scrollbar)
|
||||||
|
}
|
||||||
|
sections = append(sections, m.contentView())
|
||||||
|
if error != "" {
|
||||||
|
sections = append(sections, error)
|
||||||
|
}
|
||||||
|
sections = append(sections, m.inputView())
|
||||||
|
sections = append(sections, m.footerView())
|
||||||
|
|
||||||
return lipgloss.JoinVertical(
|
return lipgloss.JoinVertical(
|
||||||
lipgloss.Left,
|
lipgloss.Left,
|
||||||
m.headerView(),
|
sections...,
|
||||||
m.contentView(),
|
|
||||||
m.inputView(),
|
|
||||||
m.footerView(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *model) getFixedComponentHeight() int {
|
||||||
|
h := 0
|
||||||
|
h += m.input.Height()
|
||||||
|
h += lipgloss.Height(m.headerView())
|
||||||
|
h += lipgloss.Height(m.footerView())
|
||||||
|
scrollbar := m.scrollbarView()
|
||||||
|
if scrollbar != "" {
|
||||||
|
h += lipgloss.Height(scrollbar)
|
||||||
|
}
|
||||||
|
errorView := m.errorView()
|
||||||
|
if errorView != "" {
|
||||||
|
h += lipgloss.Height(errorView)
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
func (m *model) headerView() string {
|
func (m *model) headerView() string {
|
||||||
titleStyle := lipgloss.NewStyle().
|
titleStyle := lipgloss.NewStyle().
|
||||||
PaddingLeft(1).
|
PaddingLeft(1).
|
||||||
@ -258,6 +295,32 @@ func (m *model) contentView() string {
|
|||||||
return m.content.View()
|
return m.content.View()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *model) errorView() string {
|
||||||
|
if m.err == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return lipgloss.NewStyle().
|
||||||
|
Bold(true).
|
||||||
|
Foreground(lipgloss.Color("1")).
|
||||||
|
Width(m.content.Width).
|
||||||
|
AlignHorizontal(lipgloss.Center).
|
||||||
|
Render(fmt.Sprintf("%s", m.err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) scrollbarView() string {
|
||||||
|
if m.content.AtTop() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
count := int(m.content.ScrollPercent() * float64(m.content.Width-2))
|
||||||
|
fill := strings.Repeat("-", count)
|
||||||
|
return lipgloss.NewStyle().
|
||||||
|
PaddingLeft(1).
|
||||||
|
PaddingRight(1).
|
||||||
|
Width(m.content.Width).
|
||||||
|
Render(fill)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *model) inputView() string {
|
func (m *model) inputView() string {
|
||||||
return m.input.View()
|
return m.input.View()
|
||||||
}
|
}
|
||||||
@ -284,8 +347,8 @@ func (m *model) footerView() string {
|
|||||||
left := strings.Join(leftSegments, segmentSeparator)
|
left := strings.Join(leftSegments, segmentSeparator)
|
||||||
right := strings.Join(rightSegments, segmentSeparator)
|
right := strings.Join(rightSegments, segmentSeparator)
|
||||||
|
|
||||||
totalWidth := lipgloss.Width(left + right)
|
totalWidth := lipgloss.Width(left) + lipgloss.Width(right)
|
||||||
remaining := m.content.Width - totalWidth
|
remaining := m.width - totalWidth
|
||||||
|
|
||||||
var padding string
|
var padding string
|
||||||
if remaining > 0 {
|
if remaining > 0 {
|
||||||
@ -295,7 +358,7 @@ func (m *model) footerView() string {
|
|||||||
footer := left + padding + right
|
footer := left + padding + right
|
||||||
if remaining < 0 {
|
if remaining < 0 {
|
||||||
ellipses := "... "
|
ellipses := "... "
|
||||||
footer = footer[:m.content.Width-len(ellipses)] + ellipses
|
footer = footer[:m.width-len(ellipses)] + ellipses
|
||||||
}
|
}
|
||||||
return footerStyle.Render(footer)
|
return footerStyle.Render(footer)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user