Detailed changes
@@ -6,6 +6,7 @@ import (
"smoothie/tui/bubbles/commits"
"smoothie/tui/bubbles/repo"
"smoothie/tui/bubbles/selection"
+ "smoothie/tui/style"
"strings"
tea "github.com/charmbracelet/bubbletea"
@@ -48,6 +49,7 @@ type SessionConfig struct {
type Bubble struct {
config *Config
+ styles *style.Styles
state sessionState
error string
width int
@@ -66,6 +68,7 @@ type Bubble struct {
func NewBubble(cfg *Config, sCfg *SessionConfig) *Bubble {
b := &Bubble{
config: cfg,
+ styles: style.DefaultStyles(),
width: sCfg.Width,
height: sCfg.Height,
windowChanges: sCfg.WindowChanges,
@@ -143,10 +146,9 @@ func (b *Bubble) viewForBox(i int) string {
switch box := b.boxes[i].(type) {
case *selection.Bubble:
var s lipgloss.Style
+ s = b.styles.Menu
if isActive {
- s = menuActiveStyle
- } else {
- s = menuStyle
+ s.Copy().BorderForeground(b.styles.ActiveBorderColor)
}
return s.Render(box.View())
case *repo.Bubble:
@@ -158,8 +160,8 @@ func (b *Bubble) viewForBox(i int) string {
}
func (b Bubble) headerView() string {
- w := b.width - appBoxStyle.GetHorizontalFrameSize()
- return headerStyle.Copy().Width(w).Render(b.config.Name)
+ w := b.width - b.styles.App.GetHorizontalFrameSize()
+ return b.styles.Header.Copy().Width(w).Render(b.config.Name)
}
func (b Bubble) footerView() string {
@@ -179,27 +181,28 @@ func (b Bubble) footerView() string {
}
}
for i, v := range h {
- fmt.Fprint(w, v)
+ fmt.Fprint(w, v.Render(b.styles))
if i != len(h)-1 {
- fmt.Fprint(w, helpDivider)
+ fmt.Fprint(w, b.styles.HelpDivider)
}
}
- return footerStyle.Copy().Width(b.width).Render(w.String())
+ return b.styles.Footer.Copy().Width(b.width).Render(w.String())
}
func (b Bubble) errorView() string {
- s := lipgloss.JoinHorizontal(
+ s := b.styles
+ str := lipgloss.JoinHorizontal(
lipgloss.Top,
- errorHeaderStyle.Render("Bummer"),
- errorBodyStyle.Render(b.error),
+ s.ErrorTitle.Render("Bummer"),
+ s.ErrorBody.Render(b.error),
)
h := b.height -
- appBoxStyle.GetVerticalFrameSize() -
+ s.App.GetVerticalFrameSize() -
lipgloss.Height(b.headerView()) -
lipgloss.Height(b.footerView()) -
- contentBoxStyle.GetVerticalFrameSize() +
- 3 // TODO: figure out why we need this
- return errorStyle.Copy().Height(h).Render(s)
+ s.RepoBody.GetVerticalFrameSize() +
+ 3 // TODO: this is repo header height -- get it dynamically
+ return s.Error.Copy().Height(h).Render(str)
}
func (b Bubble) View() string {
@@ -216,7 +219,7 @@ func (b Bubble) View() string {
}
s.WriteRune('\n')
s.WriteString(b.footerView())
- return appBoxStyle.Render(s.String())
+ return b.styles.App.Render(s.String())
}
type helpEntry struct {
@@ -224,6 +227,6 @@ type helpEntry struct {
val string
}
-func (h helpEntry) String() string {
- return fmt.Sprintf("%s %s", helpKeyStyle.Render(h.key), helpValueStyle.Render(h.val))
+func (h helpEntry) Render(s *style.Styles) string {
+ return fmt.Sprintf("%s %s", s.HelpKey.Render(h.key), s.HelpValue.Render(h.val))
}
@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"smoothie/git"
+ "smoothie/tui/style"
"strconv"
"text/template"
@@ -22,21 +23,18 @@ type ErrMsg struct {
}
type Bubble struct {
- templateObject interface{}
- repoSource *git.RepoSource
- name string
- repo *git.Repo
- readmeViewport *ViewportBubble
- readme string
- height int
- heightMargin int
- width int
- widthMargin int
- Active bool
- TitleStyle lipgloss.Style
- NoteStyle lipgloss.Style
- BodyStyle lipgloss.Style
- ActiveBorderColor lipgloss.Color
+ templateObject interface{}
+ repoSource *git.RepoSource
+ name string
+ repo *git.Repo
+ styles *style.Styles
+ readmeViewport *ViewportBubble
+ readme string
+ height int
+ heightMargin int
+ width int
+ widthMargin int
+ Active bool
// XXX: ideally, we get these from the parent as a pointer. Currently, we
// can't add a *tui.Config because it's an illegal import cycle. One
@@ -46,11 +44,12 @@ type Bubble struct {
Port int64
}
-func NewBubble(rs *git.RepoSource, name string, width, wm, height, hm int, tmp interface{}) *Bubble {
+func NewBubble(rs *git.RepoSource, name string, styles *style.Styles, width, wm, height, hm int, tmp interface{}) *Bubble {
b := &Bubble{
templateObject: tmp,
repoSource: rs,
name: name,
+ styles: styles,
heightMargin: hm,
widthMargin: wm,
readmeViewport: &ViewportBubble{
@@ -97,11 +96,11 @@ func (b *Bubble) GotoTop() {
}
func (b Bubble) headerView() string {
- ts := b.TitleStyle
- ns := b.NoteStyle
+ ts := b.styles.RepoTitle
+ ns := b.styles.RepoNote
if b.Active {
- ts = ts.Copy().BorderForeground(b.ActiveBorderColor)
- ns = ns.Copy().BorderForeground(b.ActiveBorderColor)
+ ts = ts.Copy().BorderForeground(b.styles.ActiveBorderColor)
+ ns = ns.Copy().BorderForeground(b.styles.ActiveBorderColor)
}
n := b.name
if n == "config" {
@@ -114,13 +113,14 @@ func (b Bubble) headerView() string {
}
func (b *Bubble) View() string {
+ s := b.styles
header := b.headerView()
- bs := b.BodyStyle.Copy()
+ bs := s.RepoBody.Copy()
if b.Active {
- bs = bs.BorderForeground(b.ActiveBorderColor)
+ bs = bs.BorderForeground(s.ActiveBorderColor)
}
body := bs.
- Width(b.width - b.widthMargin - b.BodyStyle.GetVerticalFrameSize()).
+ Width(b.width - b.widthMargin - s.RepoBody.GetVerticalFrameSize()).
Height(b.height - b.heightMargin - lipgloss.Height(header)).
Render(b.readmeViewport.View())
return header + body
@@ -1,8 +1,9 @@
package selection
import (
+ "smoothie/tui/style"
+
tea "github.com/charmbracelet/bubbletea"
- "github.com/charmbracelet/lipgloss"
)
type SelectedMsg struct {
@@ -16,19 +17,15 @@ type ActiveMsg struct {
}
type Bubble struct {
- NormalStyle lipgloss.Style
- SelectedStyle lipgloss.Style
- Cursor string
- Items []string
- SelectedItem int
+ Items []string
+ SelectedItem int
+ styles *style.Styles
}
-func NewBubble(items []string, normalStyle, selectedStyle lipgloss.Style, cursor string) *Bubble {
+func NewBubble(items []string, styles *style.Styles) *Bubble {
return &Bubble{
- NormalStyle: normalStyle,
- SelectedStyle: selectedStyle,
- Cursor: cursor,
- Items: items,
+ Items: items,
+ styles: styles,
}
}
@@ -40,10 +37,10 @@ func (b Bubble) View() string {
s := ""
for i, item := range b.Items {
if i == b.SelectedItem {
- s += b.Cursor
- s += b.SelectedStyle.Render(item)
+ s += b.styles.MenuCursor.String()
+ s += b.styles.SelectedMenuItem.Render(item)
} else {
- s += b.NormalStyle.Render(item)
+ s += b.styles.MenuItem.Render(item)
}
if i < len(b.Items)-1 {
s += "\n"
@@ -49,18 +49,14 @@ func (b *Bubble) setupCmd() tea.Msg {
tmplConfig = b.config
}
width := b.width
- boxLeftWidth := menuStyle.GetWidth() + menuStyle.GetHorizontalFrameSize()
+ boxLeftWidth := b.styles.Menu.GetWidth() + b.styles.Menu.GetHorizontalFrameSize()
// TODO: also send this along with a tea.WindowSizeMsg
var heightMargin = lipgloss.Height(b.headerView()) +
lipgloss.Height(b.footerView()) +
- contentBoxStyle.GetVerticalFrameSize() +
- appBoxStyle.GetVerticalMargins() +
+ b.styles.RepoBody.GetVerticalFrameSize() +
+ b.styles.App.GetVerticalMargins() +
3 // TODO: make this dynamic (this is the height of the repo info)
- rb := repo.NewBubble(b.repoSource, me.Repo, width, boxLeftWidth, b.height, heightMargin, tmplConfig)
- rb.TitleStyle = contentBoxTitleStyle
- rb.NoteStyle = contentBoxNoteStyle
- rb.BodyStyle = contentBoxStyle
- rb.ActiveBorderColor = activeBorderColor
+ rb := repo.NewBubble(b.repoSource, me.Repo, b.styles, width, boxLeftWidth, b.height, heightMargin, tmplConfig)
rb.Host = b.config.Host
rb.Port = b.config.Port
initCmd := rb.Init()
@@ -73,7 +69,7 @@ func (b *Bubble) setupCmd() tea.Msg {
b.repoMenu = append(b.repoMenu, me)
rs = append(rs, me.Name)
}
- b.repoSelect = selection.NewBubble(rs, menuItemStyle, selectedMenuItemStyle, menuCursor.String())
+ b.repoSelect = selection.NewBubble(rs, b.styles)
b.boxes[0] = b.repoSelect
/*
b.commitsLog = commits.NewBubble(
@@ -1,115 +0,0 @@
-package tui
-
-import (
- "github.com/charmbracelet/lipgloss"
-)
-
-var activeBorderColor = lipgloss.Color("62")
-var inactiveBorderColor = lipgloss.Color("236")
-
-var viewportTitleBorder = lipgloss.Border{
- Top: "─",
- Bottom: "─",
- Left: "│",
- Right: "│",
- TopLeft: "╭",
- TopRight: "┬",
- BottomLeft: "├",
- BottomRight: "┴",
-}
-
-var viewportNoteBorder = lipgloss.Border{
- Top: "─",
- Bottom: "─",
- Left: "",
- Right: "│",
- TopLeft: "",
- TopRight: "╮",
- BottomLeft: "",
- BottomRight: "┤",
-}
-
-var viewportBodyBorder = lipgloss.Border{
- Top: "",
- Bottom: "─",
- Left: "│",
- Right: "│",
- TopLeft: "",
- TopRight: "",
- BottomLeft: "╰",
- BottomRight: "╯",
-}
-
-var appBoxStyle = lipgloss.NewStyle().
- Margin(1, 2)
-
-var headerStyle = lipgloss.NewStyle().
- Foreground(lipgloss.Color("62")).
- Align(lipgloss.Right).
- PaddingRight(1).
- Bold(true)
-
-var menuStyle = lipgloss.NewStyle().
- BorderStyle(lipgloss.RoundedBorder()).
- BorderForeground(inactiveBorderColor).
- Padding(1, 2).
- MarginRight(1).
- Width(24)
-
-var menuActiveStyle = menuStyle.Copy().
- BorderStyle(lipgloss.RoundedBorder()).
- BorderForeground(activeBorderColor)
-
-var menuCursor = lipgloss.NewStyle().
- Foreground(lipgloss.Color("213")).
- SetString(">")
-
-var contentBoxTitleStyle = lipgloss.NewStyle().
- Border(viewportTitleBorder).
- BorderForeground(inactiveBorderColor).
- Padding(0, 2)
-
-var contentBoxNoteStyle = lipgloss.NewStyle().
- Border(viewportNoteBorder, true, true, true, false).
- BorderForeground(inactiveBorderColor).
- Padding(0, 2)
-
-var contentBoxStyle = lipgloss.NewStyle().
- BorderStyle(viewportBodyBorder).
- BorderForeground(inactiveBorderColor).
- PaddingRight(1)
-
-var menuItemStyle = lipgloss.NewStyle().
- Foreground(lipgloss.Color("252")).
- PaddingLeft(2)
-
-var selectedMenuItemStyle = lipgloss.NewStyle().
- Foreground(lipgloss.Color("207")).
- PaddingLeft(1)
-
-var footerStyle = lipgloss.NewStyle().
- MarginTop(1)
-
-var helpKeyStyle = lipgloss.NewStyle().
- Foreground(lipgloss.Color("241"))
-
-var helpValueStyle = lipgloss.NewStyle().
- Foreground(lipgloss.Color("239"))
-
-var errorStyle = lipgloss.NewStyle().
- Padding(1)
-
-var errorHeaderStyle = lipgloss.NewStyle().
- Foreground(lipgloss.Color("230")).
- Background(lipgloss.Color("204")).
- Bold(true).
- Padding(0, 1)
-
-var errorBodyStyle = lipgloss.NewStyle().
- Foreground(lipgloss.Color("252")).
- MarginLeft(2).
- Width(52) // for now
-
-var helpDivider = lipgloss.NewStyle().
- Foreground(lipgloss.Color("237")).
- SetString(" • ")
@@ -0,0 +1,155 @@
+package style
+
+import (
+ "github.com/charmbracelet/lipgloss"
+)
+
+// XXX: For now, this is in its own package so that it can be shared between
+// different packages without incurring an illegal import cycle.
+
+type Styles struct {
+ ActiveBorderColor lipgloss.Color
+ InactiveBorderColor lipgloss.Color
+
+ App lipgloss.Style
+ Header lipgloss.Style
+
+ Menu lipgloss.Style
+ MenuCursor lipgloss.Style
+ MenuItem lipgloss.Style
+ SelectedMenuItem lipgloss.Style
+
+ RepoTitleBorder lipgloss.Border
+ RepoNoteBorder lipgloss.Border
+ RepoBodyBorder lipgloss.Border
+
+ RepoTitle lipgloss.Style
+ RepoNote lipgloss.Style
+ RepoBody lipgloss.Style
+
+ Footer lipgloss.Style
+ HelpKey lipgloss.Style
+ HelpValue lipgloss.Style
+ HelpDivider lipgloss.Style
+
+ Error lipgloss.Style
+ ErrorTitle lipgloss.Style
+ ErrorBody lipgloss.Style
+
+ Command lipgloss.Style
+}
+
+func DefaultStyles() *Styles {
+ s := new(Styles)
+
+ s.ActiveBorderColor = lipgloss.Color("62")
+ s.InactiveBorderColor = lipgloss.Color("236")
+
+ s.App = lipgloss.NewStyle().
+ Margin(1, 2)
+
+ s.Header = lipgloss.NewStyle().
+ Foreground(lipgloss.Color("62")).
+ Align(lipgloss.Right).
+ Bold(true)
+
+ s.Menu = lipgloss.NewStyle().
+ BorderStyle(lipgloss.RoundedBorder()).
+ BorderForeground(s.InactiveBorderColor).
+ Padding(1, 2).
+ MarginRight(1).
+ Width(24)
+
+ s.MenuCursor = lipgloss.NewStyle().
+ Foreground(lipgloss.Color("213")).
+ SetString(">")
+
+ s.MenuItem = lipgloss.NewStyle().
+ Foreground(lipgloss.Color("252")).
+ PaddingLeft(2)
+
+ s.SelectedMenuItem = lipgloss.NewStyle().
+ Foreground(lipgloss.Color("207")).
+ PaddingLeft(1)
+
+ s.RepoTitleBorder = lipgloss.Border{
+ Top: "─",
+ Bottom: "─",
+ Left: "│",
+ Right: "│",
+ TopLeft: "╭",
+ TopRight: "┬",
+ BottomLeft: "├",
+ BottomRight: "┴",
+ }
+
+ s.RepoNoteBorder = lipgloss.Border{
+ Top: "─",
+ Bottom: "─",
+ Left: "",
+ Right: "│",
+ TopLeft: "",
+ TopRight: "╮",
+ BottomLeft: "",
+ BottomRight: "┤",
+ }
+
+ s.RepoBodyBorder = lipgloss.Border{
+ Top: "",
+ Bottom: "─",
+ Left: "│",
+ Right: "│",
+ TopLeft: "",
+ TopRight: "",
+ BottomLeft: "╰",
+ BottomRight: "╯",
+ }
+
+ s.RepoTitle = lipgloss.NewStyle().
+ Border(s.RepoTitleBorder).
+ BorderForeground(s.InactiveBorderColor).
+ Padding(0, 2)
+
+ s.RepoNote = lipgloss.NewStyle().
+ Border(s.RepoNoteBorder, true, true, true, false).
+ BorderForeground(s.InactiveBorderColor).
+ Padding(0, 2)
+
+ s.RepoBody = lipgloss.NewStyle().
+ BorderStyle(s.RepoBodyBorder).
+ BorderForeground(s.InactiveBorderColor).
+ PaddingRight(1)
+
+ s.Footer = lipgloss.NewStyle().
+ MarginTop(1)
+
+ s.HelpKey = lipgloss.NewStyle().
+ Foreground(lipgloss.Color("241"))
+
+ s.HelpValue = lipgloss.NewStyle().
+ Foreground(lipgloss.Color("239"))
+
+ s.HelpDivider = lipgloss.NewStyle().
+ Foreground(lipgloss.Color("237")).
+ SetString(" • ")
+
+ s.Error = lipgloss.NewStyle().
+ Padding(1)
+
+ s.ErrorTitle = lipgloss.NewStyle().
+ Foreground(lipgloss.Color("230")).
+ Background(lipgloss.Color("204")).
+ Bold(true).
+ Padding(0, 1)
+
+ s.ErrorBody = lipgloss.NewStyle().
+ Foreground(lipgloss.Color("252")).
+ MarginLeft(2).
+ Width(52) // for now
+
+ s.Command = lipgloss.NewStyle().
+ Background(lipgloss.Color("237")).
+ Foreground(lipgloss.Color("204"))
+
+ return s
+}