diff --git a/moonmath.go b/moonmath.go index 114d7b8..66d522c 100644 --- a/moonmath.go +++ b/moonmath.go @@ -1,145 +1,15 @@ package main import ( - "context" "fmt" "os" - "time" - "code.humancabbage.net/sam/moonmath/moon" - "github.com/charmbracelet/bubbles/table" + "code.humancabbage.net/sam/moonmath/tui" tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" ) -var baseStyle = lipgloss.NewStyle(). - BorderStyle(lipgloss.NormalBorder()). - BorderForeground(lipgloss.Color("240")) - -type model struct { - math moon.Math - - prices table.Model - projections table.Model -} - -func (m model) Init() tea.Cmd { - return func() tea.Msg { - _ = m.math.Refresh(context.TODO()) - return m.math - } -} - -func initialModel() model { - math := moon.NewMath(nil, nil) - - tableStyle := table.DefaultStyles() - tableStyle.Selected = lipgloss.NewStyle() - prices := table.New( - table.WithColumns([]table.Column{ - {Title: "Price", Width: 9}, - }), - table.WithHeight(1), - table.WithStyles(tableStyle), - ) - - projectionCols := []table.Column{ - {Title: "Labels", Width: 8}, - } - for i := range math.Columns { - projectionCols = append(projectionCols, table.Column{ - Title: math.Columns[i].Base.Name(), - Width: 10, - }) - } - projectionRows := make([]table.Row, len(math.Goals)+2) - for i := range projectionRows { - projectionRows[i] = make(table.Row, len(projectionCols)) - } - projectionRows[0][0] = "Starting" - projectionRows[1][0] = "CDPR" - for i := range math.Goals { - projectionRows[i+2][0] = fmt.Sprintf("$%.0f", math.Goals[i]) - } - projections := table.New( - table.WithColumns(projectionCols), - table.WithRows(projectionRows), - table.WithHeight(len(math.Goals)+2), - table.WithStyles(tableStyle), - ) - - return model{ - math: math, - prices: prices, - projections: projections, - } -} - -func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case moon.Math: - m.math = msg - refillPrice(&m) - refillProjections(&m) - return m, tea.Tick(time.Second*30, func(t time.Time) tea.Msg { - _ = m.math.Refresh(context.TODO()) - return m.math - }) - case tea.KeyMsg: - switch msg.String() { - case "ctrl+c", "q", "esc": - return m, tea.Quit - } - } - return m, nil -} - -func refillPrice(m *model) { - rows := []table.Row{ - []string{fmt.Sprintf("$%0.2f", m.math.CurrentPrice)}, - } - m.prices.SetRows(rows) -} - -func refillProjections(m *model) { - rows := m.projections.Rows() - - for col := range m.math.Columns { - _ = col - never := false - if m.math.Columns[col].CDPR <= 1 { - never = true - } - - rows[0][col+1] = fmt.Sprintf("$%.2f", m.math.Columns[col].StartingPrice) - rows[1][col+1] = fmt.Sprintf("%.2f%%", (m.math.Columns[col].CDPR-1)*100) - for row := 0; row < len(m.math.Goals); row++ { - var cell string - if never { - cell = "NEVER!!!!!" - } else { - cell = m.math.Columns[col]. - Projections.Dates[row]. - Format("2006-01-02") - } - rows[row+2][col+1] = cell - } - } - m.projections.SetRows(rows) -} - -func (m model) View() string { - var s string - s += lipgloss.JoinHorizontal( - lipgloss.Top, - baseStyle.Render(m.prices.View()), - baseStyle.Render(m.projections.View()), - ) - return s + "\n" -} - func main() { - p := tea.NewProgram(initialModel()) + p := tea.NewProgram(tui.New()) if _, err := p.Run(); err != nil { fmt.Printf("program error: %v\n", err) os.Exit(1) diff --git a/tui/tui.go b/tui/tui.go new file mode 100644 index 0000000..2001632 --- /dev/null +++ b/tui/tui.go @@ -0,0 +1,138 @@ +package tui + +import ( + "context" + "fmt" + "time" + + "code.humancabbage.net/sam/moonmath/moon" + "github.com/charmbracelet/bubbles/table" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +var baseStyle = lipgloss.NewStyle(). + BorderStyle(lipgloss.NormalBorder()). + BorderForeground(lipgloss.Color("240")) + +type Model struct { + math moon.Math + + prices table.Model + projections table.Model +} + +func New() Model { + math := moon.NewMath(nil, nil) + + tableStyle := table.DefaultStyles() + tableStyle.Selected = lipgloss.NewStyle() + prices := table.New( + table.WithColumns([]table.Column{ + {Title: "Price", Width: 9}, + }), + table.WithHeight(1), + table.WithStyles(tableStyle), + ) + + projectionCols := []table.Column{ + {Title: "Labels", Width: 8}, + } + for i := range math.Columns { + projectionCols = append(projectionCols, table.Column{ + Title: math.Columns[i].Base.Name(), + Width: 10, + }) + } + projectionRows := make([]table.Row, len(math.Goals)+2) + for i := range projectionRows { + projectionRows[i] = make(table.Row, len(projectionCols)) + } + projectionRows[0][0] = "Starting" + projectionRows[1][0] = "CDPR" + for i := range math.Goals { + projectionRows[i+2][0] = fmt.Sprintf("$%.0f", math.Goals[i]) + } + projections := table.New( + table.WithColumns(projectionCols), + table.WithRows(projectionRows), + table.WithHeight(len(math.Goals)+2), + table.WithStyles(tableStyle), + ) + + return Model{ + math: math, + prices: prices, + projections: projections, + } +} + +func (m Model) Init() tea.Cmd { + return func() tea.Msg { + _ = m.math.Refresh(context.TODO()) + return m.math + } +} + +func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case moon.Math: + m.math = msg + refillPrice(&m) + refillProjections(&m) + return m, tea.Tick(time.Second*30, func(t time.Time) tea.Msg { + _ = m.math.Refresh(context.TODO()) + return m.math + }) + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "q", "esc": + return m, tea.Quit + } + } + return m, nil +} + +func refillPrice(m *Model) { + rows := []table.Row{ + []string{fmt.Sprintf("$%0.2f", m.math.CurrentPrice)}, + } + m.prices.SetRows(rows) +} + +func refillProjections(m *Model) { + rows := m.projections.Rows() + + for col := range m.math.Columns { + _ = col + never := false + if m.math.Columns[col].CDPR <= 1 { + never = true + } + + rows[0][col+1] = fmt.Sprintf("$%.2f", m.math.Columns[col].StartingPrice) + rows[1][col+1] = fmt.Sprintf("%.2f%%", (m.math.Columns[col].CDPR-1)*100) + for row := 0; row < len(m.math.Goals); row++ { + var cell string + if never { + cell = "NEVER!!!!!" + } else { + cell = m.math.Columns[col]. + Projections.Dates[row]. + Format("2006-01-02") + } + rows[row+2][col+1] = cell + } + } + m.projections.SetRows(rows) +} + +func (m Model) View() string { + var s string + s += lipgloss.JoinHorizontal( + lipgloss.Top, + baseStyle.Render(m.prices.View()), + baseStyle.Render(m.projections.View()), + ) + return s + "\n" +}