@@ -23,7 +23,7 @@ func Scrollbar(s *styles.Styles, height, contentSize, viewportSize, offset int)
}
// Calculate where the thumb starts.
- trackSpace := height - thumbSize
+ trackSpace := height - thumbSize + 1
thumbPos := 0
if trackSpace > 0 && maxOffset > 0 {
thumbPos = min(trackSpace, offset*trackSpace/maxOffset)
@@ -10,6 +10,7 @@ import (
"charm.land/bubbles/v2/textinput"
tea "charm.land/bubbletea/v2"
"charm.land/catwalk/pkg/catwalk"
+ "charm.land/lipgloss/v2"
"github.com/charmbracelet/crush/internal/config"
"github.com/charmbracelet/crush/internal/ui/common"
"github.com/charmbracelet/crush/internal/ui/util"
@@ -265,9 +266,14 @@ func (m *Models) Draw(scr uv.Screen, area uv.Rectangle) *tea.Cursor {
t.Dialog.View.GetVerticalFrameSize()
m.input.SetWidth(max(0, innerWidth-t.Dialog.InputPrompt.GetHorizontalFrameSize()-1)) // (1) cursor padding
- m.list.SetSize(innerWidth, height-heightOffset)
m.help.SetWidth(innerWidth)
+ listHeight := height - heightOffset
+ m.list.SetSize(innerWidth, listHeight)
+ listTotalHeight := m.list.TotalHeight()
+ listWidth := max(0, innerWidth-3) // Reserve space for scrollbar.
+ m.list.SetSize(listWidth, listHeight)
+
rc := NewRenderContext(t, width)
rc.Title = "Switch Model"
rc.TitleInfo = m.modelTypeRadioView()
@@ -281,6 +287,10 @@ func (m *Models) Draw(scr uv.Screen, area uv.Rectangle) *tea.Cursor {
rc.AddPart(inputView)
listView := t.Dialog.List.Height(m.list.Height()).Render(m.list.Render())
+ scrollbar := common.Scrollbar(t, listHeight, listTotalHeight, listHeight, m.list.Offset())
+ if scrollbar != "" {
+ listView = lipgloss.JoinHorizontal(lipgloss.Top, listView, scrollbar)
+ }
rc.AddPart(listView)
rc.Help = m.help.View(m)
@@ -157,6 +157,33 @@ func (l *List) Len() int {
return len(l.items)
}
+// TotalHeight returns the total height of all items in the list.
+func (l *List) TotalHeight() int {
+ total := 0
+ for idx := range l.items {
+ item := l.getItem(idx)
+ total += item.height
+ if l.gap > 0 && idx < len(l.items)-1 {
+ total += l.gap
+ }
+ }
+ return total
+}
+
+// Offset returns the current scroll offset in lines from the top.
+func (l *List) Offset() int {
+ offset := 0
+ for idx := 0; idx < l.offsetIdx; idx++ {
+ item := l.getItem(idx)
+ offset += item.height
+ if l.gap > 0 && idx < len(l.items)-1 {
+ offset += l.gap
+ }
+ }
+ offset += l.offsetLine
+ return offset
+}
+
// lastOffsetItem returns the index and line offsets of the last item that can
// be partially visible in the viewport.
func (l *List) lastOffsetItem() (int, int, int) {