scrollbar.go 1.1 KB

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