scrollbar.go

 1package common
 2
 3import (
 4	"strings"
 5
 6	"github.com/charmbracelet/crush/internal/ui/styles"
 7)
 8
 9// Scrollbar renders a vertical scrollbar based on content and viewport size.
10// Returns an empty string if content fits within viewport (no scrolling needed).
11func Scrollbar(s *styles.Styles, height, contentSize, viewportSize, offset int) string {
12	if height <= 0 || contentSize <= viewportSize {
13		return ""
14	}
15
16	// Calculate thumb size (minimum 1 character).
17	thumbSize := max(1, height*viewportSize/contentSize)
18
19	// Calculate thumb position.
20	maxOffset := contentSize - viewportSize
21	if maxOffset <= 0 {
22		return ""
23	}
24
25	// Calculate where the thumb starts.
26	trackSpace := height - thumbSize
27	thumbPos := 0
28	if trackSpace > 0 && maxOffset > 0 {
29		thumbPos = min(trackSpace, offset*trackSpace/maxOffset)
30	}
31
32	// Build the scrollbar.
33	var sb strings.Builder
34	for i := range height {
35		if i > 0 {
36			sb.WriteString("\n")
37		}
38		if i >= thumbPos && i < thumbPos+thumbSize {
39			sb.WriteString(s.Dialog.ScrollbarThumb.Render(styles.ScrollbarThumb))
40		} else {
41			sb.WriteString(s.Dialog.ScrollbarTrack.Render(styles.ScrollbarTrack))
42		}
43	}
44
45	return sb.String()
46}