From afe7e9f0a94c19d35a299ae449075931cadf86c7 Mon Sep 17 00:00:00 2001 From: Topvennie Date: Sun, 22 Dec 2024 16:57:56 +0100 Subject: [PATCH] chore(zess): better dynamic scaling --- tui/screen/cammie/cammie.go | 27 +++----- tui/view/song/style.go | 2 +- tui/view/zess/style.go | 124 +++++++++++++++++++++++++++--------- tui/view/zess/view.go | 25 ++++---- tui/view/zess/zess.go | 30 +++++++-- 5 files changed, 141 insertions(+), 67 deletions(-) diff --git a/tui/screen/cammie/cammie.go b/tui/screen/cammie/cammie.go index bbb1ee3..dd7fa35 100644 --- a/tui/screen/cammie/cammie.go +++ b/tui/screen/cammie/cammie.go @@ -98,20 +98,20 @@ func (c *Cammie) View() string { // Render top // Render tabs - var topTabs []string + var tabs []string for i, view := range c.top { if i == c.indexTop { - topTabs = append(topTabs, sActiveTab.Render(view.Name())) + tabs = append(tabs, sActiveTab.Render(view.Name())) } else { - topTabs = append(topTabs, sTabNormal.Render(view.Name())) + tabs = append(tabs, sTabNormal.Render(view.Name())) } } - topTab := lipgloss.JoinHorizontal(lipgloss.Bottom, topTabs...) - topTabsLine := sTabNormal.Render(strings.Repeat(" ", max(0, (c.width/2)-lipgloss.Width(topTab)-10))) - topTab = lipgloss.JoinHorizontal(lipgloss.Bottom, topTab, topTabsLine) + tab := lipgloss.JoinHorizontal(lipgloss.Bottom, tabs...) + tabLine := sTabNormal.Render(strings.Repeat(" ", max(0, sTop.GetWidth()-lipgloss.Width(tab)-2))) // -2 comes from sTab padding + tab = lipgloss.JoinHorizontal(lipgloss.Bottom, tab, tabLine) // Render top view - top := lipgloss.JoinVertical(lipgloss.Left, topTab, c.top[c.indexTop].View()) + top := lipgloss.JoinVertical(lipgloss.Left, tab, c.top[c.indexTop].View()) top = sTop.Render(top) // Render bottom @@ -144,18 +144,11 @@ func (c *Cammie) GetUpdateViews() []view.UpdateData { func (c *Cammie) GetSizeMsg() tea.Msg { sizes := make(map[string]view.Size) - msgW := sMsg.GetWidth() - msgH := sMsg.GetHeight() - sizes[c.messages.Name()] = view.Size{Width: msgW, Height: msgH} - - bottomW := sBottom.GetWidth() - bottomH := sBottom.GetHeight() - sizes[c.bottom.Name()] = view.Size{Width: bottomW, Height: bottomH} + sizes[c.messages.Name()] = view.Size{Width: sMsg.GetWidth(), Height: sMsg.GetHeight()} + sizes[c.bottom.Name()] = view.Size{Width: sBottom.GetWidth(), Height: sBottom.GetHeight()} for _, top := range c.top { - topW := sTop.GetWidth() - topH := sTop.GetHeight() - sizes[top.Name()] = view.Size{Width: topW, Height: topH} + sizes[top.Name()] = view.Size{Width: sTop.GetWidth(), Height: sTop.GetHeight() - view.GetOuterHeight(sTop) - view.GetOuterHeight(sTab)} } return view.MsgSize{Sizes: sizes} diff --git a/tui/view/song/style.go b/tui/view/song/style.go index f9b0f90..67f987b 100644 --- a/tui/view/song/style.go +++ b/tui/view/song/style.go @@ -29,7 +29,7 @@ var base = lipgloss.NewStyle() var ( // Widths wStatEnum = 3 - wStatAmount = 4 + wStatAmount = 4 // Supports up to 1000 wStatEntryMax = 35 // Styles diff --git a/tui/view/zess/style.go b/tui/view/zess/style.go index fe6f3ad..874c9d9 100644 --- a/tui/view/zess/style.go +++ b/tui/view/zess/style.go @@ -1,32 +1,55 @@ package zess -import "github.com/charmbracelet/lipgloss" +import ( + "github.com/charmbracelet/lipgloss" + "github.com/zeusWPI/scc/tui/view" +) + +// Colors +var ( + cBorder = lipgloss.Color("#383838") + cZeus = lipgloss.Color("#FF7F00") + cStatsTitle = lipgloss.Color("#EE4B2B") +) +// Base style var base = lipgloss.NewStyle() -// Width +// Styles for the barchart var ( - widthAmount = 5 - widthWeek = 8 -) + // Widths + wBarGap = 1 // Gap between bars + wBar = 5 // Width of a bar + wBarMin = 3 // Required for the bar label, for example 'W56' + wBarAmountMax = 10 // Maximum amount of bars -// Margin -var mOverview = 2 + sBar = base + sBarOne = base + sBarLabel = base.Align(lipgloss.Center) +) -// Barchart +// Styles for the stats var ( - widthBar = 60 - heightBar = 20 + // Widths + wStatDate = 11 // 11 characters, for example 'W56 - 29/12' + wStatAmount = 4 // Supports up to 9999 + wStatGapMin = 3 // Minumum gap size between the date and amount + + sStat = base.BorderStyle(lipgloss.ThickBorder()).BorderForeground(cBorder).BorderLeft(true).MarginLeft(1).PaddingLeft(1) + sStatTitle = base.Foreground(cStatsTitle).Bold(true).BorderStyle(lipgloss.NormalBorder()).BorderForeground(cBorder).BorderBottom(true).Align(lipgloss.Center).MarginBottom(1) + sStatDate = base.Width(wStatDate) + sStatAmount = base.Width(wStatAmount) + sStatTotal = base.BorderStyle(lipgloss.NormalBorder()).BorderForeground(cBorder).BorderTop(true).MarginTop(1) + sStatTotalTitle = sStatDate.Bold(true) + sStatTotalAmount = sStatAmount.Bold(true) ) -// Colors +// Styles for the max amount var ( - cBorder = lipgloss.Color("#383838") - cZeus = lipgloss.Color("#FF7F00") - cStatsTitle = lipgloss.Color("#EE4B2B") + sMax = base.Foreground(cZeus).Bold(true) ) -// Message colors +// Bar colors var colors = []string{ "#FAF500", // Yellow "#3AFA00", // Green @@ -51,19 +74,60 @@ var colors = []string{ "#B3D2F9", // Boring Blue } -// Styles chart -var ( - sBar = base -) +// updateStyles updates all the affected styles when a size update message is received +func (m *Model) updateStyles() { + if m.width-wStatDate-wStatAmount-wStatGapMin < 0 { + // Screen is way too small + // Avoid entering an infinite loop down below + return + } -// Styles stats -var ( - sStats = base.Border(lipgloss.NormalBorder(), false, false, false, true).BorderForeground(cBorder).MarginLeft(mOverview).PaddingLeft(mOverview) - sStatsTitle = base.Foreground(cStatsTitle).Bold(true).Border(lipgloss.NormalBorder(), false, false, true, false).BorderForeground(cBorder).Width(widthAmount + widthWeek).Align(lipgloss.Center) - sStatsWeek = base.Width(widthWeek) - sStatsAmount = base.Bold(true).Width(widthAmount).Align(lipgloss.Right) - sStatsAmountMax = sStatsAmount.Foreground(cZeus) - sStatsTotal = base.Border(lipgloss.NormalBorder(), true, false, false, false).BorderForeground(cBorder).MarginTop(1) - sStatsTotalTitle = sStatsWeek - sStatsTotalAmount = sStatsAmount -) + // Adjust bar styles + + wBar = wBarMin + wStatWithoutGap := wStatDate + wStatAmount + view.GetOuterWidth(sStat) + for (m.width-wStatWithoutGap-wStatGapMin-wBarAmountMax*wBarGap)/wBar >= wBarAmountMax { + wBar++ + } + bars := (m.width - wStatWithoutGap - wStatGapMin) / wBar + sBar = sBar.Width(bars * wBar).Height(m.height - view.GetOuterHeight(sBar)) + sBarLabel = sBarLabel.Width(wBar) + + // Adjust stat styles + wStatGap := m.width - wStatWithoutGap - (bars * wBar) + wStat := wStatDate + wStatGap + wStatAmount + + sStat = sStat.Width(wStat + view.GetOuterWidth(sStat)).Height(m.height).MaxHeight(m.height) + sStatTitle = sStatTitle.Width(wStat) + sStatDate = sStatDate.Width(sStatDate.GetWidth() + wStatGap) + sStatTotal = sStatTotal.Width(sStatTitle.GetWidth()) + sStatTotalTitle = sStatTotalTitle.Width(sStatDate.GetWidth()) + +} + +// // Width +// var ( +// widthAmount = 5 +// widthWeek = 8 +// ) + +// // Margin +// var mOverview = 2 + +// // Barchart +// var ( +// widthBar = 60 +// heightBar = 20 +// ) + +// // Styles stats +// var ( +// sStats = base.Border(lipgloss.NormalBorder(), false, false, false, true).BorderForeground(cBorder).MarginLeft(mOverview).PaddingLeft(mOverview) +// sStatsTitle = base.Foreground(cStatsTitle).Bold(true).Border(lipgloss.NormalBorder(), false, false, true, false).BorderForeground(cBorder).Width(widthAmount + widthWeek).Align(lipgloss.Center) +// sStatsWeek = base.Width(widthWeek) +// sStatsAmount = base.Bold(true).Width(widthAmount).Align(lipgloss.Right) +// sStatsAmountMax = sStatsAmount.Foreground(cZeus) +// sStatsTotal = base.Border(lipgloss.NormalBorder(), true, false, false, false).BorderForeground(cBorder).MarginTop(1) +// sStatsTotalTitle = sStatsWeek +// sStatsTotalAmount = sStatsAmount +// ) diff --git a/tui/view/zess/view.go b/tui/view/zess/view.go index 6828146..e130254 100644 --- a/tui/view/zess/view.go +++ b/tui/view/zess/view.go @@ -1,6 +1,7 @@ package zess import ( + "fmt" "strconv" "github.com/NimbleMarkets/ntcharts/barchart" @@ -8,15 +9,15 @@ import ( ) func (m *Model) viewChart() string { - chart := barchart.New(widthBar, heightBar) + chart := barchart.New(sBar.GetWidth(), sBar.GetHeight(), barchart.WithNoAutoBarWidth(), barchart.WithBarGap(0), barchart.WithBarWidth(wBar)) for _, scan := range m.scans { bar := barchart.BarData{ - Label: scan.label, + Label: sBarLabel.Render(fmt.Sprintf("W%d", scan.time.week)), Values: []barchart.BarValue{{ - Name: scan.label, + Name: scan.start, Value: float64(scan.amount), - Style: sBar.Foreground(lipgloss.Color(scan.color)), + Style: sBarOne.Foreground(lipgloss.Color(scan.color)), }}, } @@ -33,13 +34,13 @@ func (m *Model) viewStats() string { rows := make([]string, 0, len(m.scans)) for _, scan := range m.scans { - week := sStatsWeek.Render(scan.label) + week := sStatDate.Render(fmt.Sprintf("W%d - %s", scan.time.week, scan.start)) var amount string if scan.amount == m.maxWeekScans { - amount = sStatsAmountMax.Render(strconv.Itoa(int(scan.amount))) + amount = sMax.Inherit(sStatAmount).Render(strconv.Itoa(int(scan.amount))) } else { - amount = sStatsAmount.Render(strconv.Itoa(int(scan.amount))) + amount = sStatAmount.Render(strconv.Itoa(int(scan.amount))) } text := lipgloss.JoinHorizontal(lipgloss.Top, week, amount) @@ -49,15 +50,15 @@ func (m *Model) viewStats() string { view := lipgloss.JoinVertical(lipgloss.Left, rows...) // Title - title := sStatsTitle.Render("Overview") + title := sStatTitle.Render("Overview") // Total scans - total := sStatsTotalTitle.Render("Total") - amount := sStatsTotalAmount.Render(strconv.Itoa(int(m.seasonScans))) + total := sStatTotalTitle.Render("Total") + amount := sStatTotalAmount.Render(strconv.Itoa(int(m.seasonScans))) total = lipgloss.JoinHorizontal(lipgloss.Top, total, amount) - total = sStatsTotal.Render(total) + total = sStatTotal.Render(total) view = lipgloss.JoinVertical(lipgloss.Left, title, view, total) - return view + return sStat.Render(view) } diff --git a/tui/view/zess/zess.go b/tui/view/zess/zess.go index a8d8c9d..34a0850 100644 --- a/tui/view/zess/zess.go +++ b/tui/view/zess/zess.go @@ -14,7 +14,7 @@ import ( "go.uber.org/zap" ) -// yearWeek represents a yearWeek object by keeping the year and week number +// yearWeek is used to represent a date by it's year and week type yearWeek struct { year int week int @@ -23,7 +23,7 @@ type yearWeek struct { type weekScan struct { time yearWeek amount int64 - label string + start string // The date when the week starts color string } @@ -36,6 +36,9 @@ type Model struct { maxWeekScans int64 currentSeason yearWeek // Start week of the season seasonScans int64 + + width int + height int } // Msg is the base message to indicate that something changed in the zess view @@ -98,6 +101,19 @@ func (m *Model) Name() string { // Update updates the zess model func (m *Model) Update(msg tea.Msg) (view.View, tea.Cmd) { switch msg := msg.(type) { + case view.MsgSize: + // Size update! + // Check if it's relevant for this view + entry, ok := msg.Sizes[m.Name()] + if ok { + // Update all dependent styles + m.width = entry.Width + m.height = entry.Height + + m.updateStyles() + } + + return m, nil // New scan(s) case scanMsg: m.lastScanID = msg.lastScanID @@ -164,13 +180,13 @@ func (m *Model) Update(msg tea.Msg) (view.View, tea.Cmd) { // View returns the view for the zess model func (m *Model) View() string { chart := m.viewChart() - overview := m.viewStats() + stats := m.viewStats() - // Give them the same height - overview = sStats.Height(lipgloss.Height(chart)).Render(overview) + // // Give them the same height + // stats = sStat.Height(lipgloss.Height(chart)).Render(stats) // Join them together - view := lipgloss.JoinHorizontal(lipgloss.Top, chart, overview) + view := lipgloss.JoinHorizontal(lipgloss.Top, chart, stats) return view } @@ -232,7 +248,7 @@ func updateScans(view view.View) (tea.Msg, error) { zessScanMsg.scans = append(zessScanMsg.scans, weekScan{ time: newTime, amount: 1, - label: newScan.ScanTime.Time.Format("02/01"), + start: newScan.ScanTime.Time.Format("02/01"), color: randomColor(), }) }