From 71f052a558f808c8c58f599aa6e8afb2d0856938 Mon Sep 17 00:00:00 2001 From: Topvennie Date: Mon, 23 Dec 2024 16:29:00 +0100 Subject: [PATCH] chore(event): better dynamic scaling --- tui/view/event/event.go | 19 ++++++- tui/view/event/style.go | 115 ++++++++++++++++++++++++++-------------- tui/view/event/view.go | 103 +++++++++++++++++------------------ 3 files changed, 141 insertions(+), 96 deletions(-) diff --git a/tui/view/event/event.go b/tui/view/event/event.go index 755ad70..ad7e32e 100644 --- a/tui/view/event/event.go +++ b/tui/view/event/event.go @@ -24,6 +24,9 @@ type Model struct { passed []dto.Event upcoming []dto.Event today *dto.Event + + width int + height int } // Msg represents the message to update the event view @@ -51,6 +54,20 @@ func (m *Model) Name() string { // Update updates the event model view 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 + case Msg: m.passed = msg.passed m.upcoming = msg.upcoming @@ -66,7 +83,7 @@ func (m *Model) View() string { return m.viewToday() } - return m.viewNormal() + return m.viewOverview() } // GetUpdateDatas returns all the update function for the event model diff --git a/tui/view/event/style.go b/tui/view/event/style.go index bfbfbc9..87a0f71 100644 --- a/tui/view/event/style.go +++ b/tui/view/event/style.go @@ -1,27 +1,8 @@ package event -import "github.com/charmbracelet/lipgloss" - -// Widths -var ( - widthToday = 45 - widthImage = 32 - - widthOverview = 45 - widthOverviewName = 35 - widthOverviewImage = 32 -) - -// Base -var ( - base = lipgloss.NewStyle() - baseToday = base.Width(widthToday).Align(lipgloss.Center) -) - -// Margins -var ( - mTodayWarning = 3 - mOverview = 5 +import ( + "github.com/charmbracelet/lipgloss" + "github.com/zeusWPI/scc/tui/view" ) // Color @@ -32,26 +13,80 @@ var ( cUpcoming = lipgloss.Color("#FFBF00") ) -// Styles today +// Base style +var base = lipgloss.NewStyle() + +// Styles for overview var ( - sTodayWarning = baseToday.Bold(true).Blink(true).Foreground(cWarning).Border(lipgloss.DoubleBorder(), true, false) - sTodayName = baseToday.Bold(true).Foreground(cZeus).BorderStyle(lipgloss.NormalBorder()).BorderBottom(true).BorderForeground(cBorder) - sTodayTime = baseToday - sTodayPlace = baseToday.Italic(true).Faint(true) - sToday = baseToday.MarginLeft(8).AlignVertical(lipgloss.Center) + wOvDate = 8 // Width of the date, for example '13/11' (with some padding after) + wOvTextMin = 20 // Minimum width of the event name + wOvPoster = 20 // Width of the poster + wOvGap = 2 // Width of the gap between the overview and the poster + + sOvAll = base.Padding(0, 1) // Style for the overview and the poster + sOvPoster = base.AlignVertical(lipgloss.Center) + sOv = base.AlignVertical(lipgloss.Center).MarginRight(wOvGap) // Style for the overview of the events + sOvTitle = base.Bold(true).Foreground(cWarning).Align(lipgloss.Center).BorderStyle(lipgloss.NormalBorder()).BorderBottom(true).BorderForeground(cBorder) + + // Styles for passed events + sOvPassedDate = base.Width(wOvDate).Faint(true) + sOvPassedText = base.Foreground(cZeus).Faint(true) + + // Styles for next event + sOvNextDate = base.Width(wOvDate).Bold(true) + sOvNextText = base.Bold(true).Foreground(cZeus) + sOvNextLoc = base.Italic(true) + + // Styles for the upcoming envets + sOvUpcomingDate = base.Width(wOvDate).Faint(true) + sOvUpcomingText = base.Foreground(cUpcoming) + sOvUpcomingLoc = base.Italic(true).Faint(true) ) -// Styles overview +// Styles for today var ( - sOverviewTotal = base.AlignVertical(lipgloss.Center) - sOverviewTitle = base.Bold(true).Foreground(cWarning).Width(widthOverview).Align(lipgloss.Center) - sOverview = base.Border(lipgloss.NormalBorder(), true, false, false, false).BorderForeground(cBorder).Width(widthOverview).MarginRight(mOverview) - sPassedName = base.Foreground(cZeus).Faint(true).Width(widthOverviewName) - sPassedTime = base.Faint(true) - sNextName = base.Bold(true).Foreground(cZeus).Width(widthOverviewName) - sNextTime = base.Bold(true) - sNextPlace = base.Italic(true).Width(widthOverviewName) - sUpcomingName = base.Width(widthOverviewName).Foreground(cUpcoming) - sUpcomingTime = base.Faint(true) - sUpcomingPlace = base.Italic(true).Faint(true).Width(widthOverviewName) + wTodayEvMin = 20 // Minimum width of the event + wTodayPoster = 20 // Width of the poster + wTodayGap = 2 // Width of the gap between the text and the poster + + sTodayAll = base.Padding(0, 1) // Style for the text and the poster + sTodayPoster = base.AlignVertical(lipgloss.Center) + sToday = base.AlignVertical(lipgloss.Center).MarginLeft(wOvGap).Padding(1, 0).Border(lipgloss.DoubleBorder(), true, false) // Style for the event + + sTodayDate = base.Align(lipgloss.Center) + sTodayText = base.Align(lipgloss.Center).Bold(true).Foreground(cZeus).BorderStyle(lipgloss.NormalBorder()).BorderBottom(true).BorderForeground(cBorder) + sTodayeLoc = base.Align(lipgloss.Center).Italic(true).Faint(true) ) + +func (m *Model) updateStyles() { + // Adjust the styles for the overview + wOvPoster = (m.width - wOvGap - view.GetOuterWidth(sOvAll)) / 2 + if wOvPoster <= wOvDate+wOvTextMin { + // Screen is too small, don't draw the poster for more space + wOvPoster = 0 + } + + wOv := wOvPoster + wOvText := wOv - wOvDate + + sOv = sOv.Width(wOv) + sOvTitle = sOvTitle.Width(wOv) + sOvPassedText = sOvPassedText.Width(wOvText) + sOvNextText = sOvNextText.Width(wOvText) + sOvNextLoc = sOvNextLoc.Width(wOvText) + sOvUpcomingText = sOvUpcomingText.Width(wOvText) + sOvUpcomingLoc = sOvUpcomingLoc.Width(wOvText) + + // Adjust the styles for today + wTodayPoster = (m.width - wTodayGap - view.GetOuterWidth(sTodayAll)) / 2 + if wTodayPoster <= wTodayEvMin { + // Screen is too small, don't draw the poster for more space + wTodayPoster = 0 + } + + wTodayEv := wTodayPoster + + sTodayDate = sTodayDate.Width(wTodayEv) + sTodayText = sTodayText.Width(wTodayEv) + sTodayeLoc = sTodayeLoc.Width(wTodayEv) +} diff --git a/tui/view/event/view.go b/tui/view/event/view.go index 7d3a16c..94e3816 100644 --- a/tui/view/event/view.go +++ b/tui/view/event/view.go @@ -10,107 +10,100 @@ import ( func (m *Model) viewToday() string { // Render image - im := "" + poster := "" if m.today.Poster != nil { i, _, err := image.Decode(bytes.NewReader(m.today.Poster)) if err == nil { - im = view.ImagetoString(widthImage, i) + poster = view.ImagetoString(wTodayPoster, i) } } - // Render text - warningTop := sTodayWarning.MarginBottom(mTodayWarning).Render("🥳 Event Today 🥳") - warningBottom := sTodayWarning.MarginTop(mTodayWarning).Render("🥳 Event Today 🥳") + name := sTodayText.Render(m.today.Name) + date := sTodayDate.Render("🕙 " + m.today.Date.Format("15:04")) + location := sTodayeLoc.Render("📍 " + m.today.Location) - name := sTodayName.Render(m.today.Name) - time := sTodayTime.Render("🕙 " + m.today.Date.Format("15:04")) - location := sTodayPlace.Render("📍 " + m.today.Location) + event := lipgloss.JoinVertical(lipgloss.Left, name, date, location) + event = sToday.Render(event) - text := lipgloss.JoinVertical(lipgloss.Left, warningTop, name, time, location, warningBottom) - - // Resize so it's centered - if lipgloss.Height(im) > lipgloss.Height(text) { - sToday = sToday.Height(lipgloss.Height(im)) + if lipgloss.Height(poster) > lipgloss.Height(event) { + event = sTodayPoster.Height(lipgloss.Height(poster)).Render(event) + } else { + poster = sTodayPoster.Height(lipgloss.Height(event)).Render(poster) } - text = sToday.Render(text) - return lipgloss.JoinHorizontal(lipgloss.Top, im, text) + view := lipgloss.JoinHorizontal(lipgloss.Top, poster, event) + + return sTodayAll.Render(view) } -func (m *Model) viewNormal() string { +func (m *Model) viewOverview() string { // Poster if present - im := "" + poster := "" if len(m.upcoming) > 0 && m.upcoming[0].Poster != nil { i, _, err := image.Decode(bytes.NewReader(m.upcoming[0].Poster)) if err == nil { - im = view.ImagetoString(widthOverviewImage, i) + poster = view.ImagetoString(wOvPoster, i) } } // Overview - events := m.viewGetEvents() - - // Filthy hack to avoid the last event being centered by the cammie screen - events = append(events, "\n") + events := m.viewGetEventOverview() - // Render events overview - overview := lipgloss.JoinVertical(lipgloss.Left, events...) - overview = sOverview.Render(overview) - - title := sOverviewTitle.Render("Events") - overview = lipgloss.JoinVertical(lipgloss.Left, title, overview) - - // Center the overview - if lipgloss.Height(im) > lipgloss.Height(overview) { - overview = sOverviewTotal.Height(lipgloss.Height(im)).Render(overview) + if lipgloss.Height(poster) > lipgloss.Height(events) { + events = sOv.Height(lipgloss.Height(poster)).Render(events) + } else { + poster = sOvPoster.Height(lipgloss.Height(events)).Render(poster) } // Combine image and overview - view := lipgloss.JoinHorizontal(lipgloss.Top, overview, im) + view := lipgloss.JoinHorizontal(lipgloss.Top, events, poster) - return view + return sOvAll.Render(view) } -func (m *Model) viewGetEvents() []string { - events := make([]string, 0, len(m.passed)+len(m.upcoming)) +func (m *Model) viewGetEventOverview() string { + events := make([]string, 0, len(m.passed)+len(m.upcoming)+1) + + title := sOvTitle.Render("Events") + events = append(events, title) // Passed for _, event := range m.passed { - time := sPassedTime.Render(event.Date.Format("02/01") + "\t") - name := sPassedName.Render(event.Name) - text := lipgloss.JoinHorizontal(lipgloss.Top, time, name) + date := sOvPassedDate.Render(event.Date.Format("02/01")) + name := sOvPassedText.Render(event.Name) + text := lipgloss.JoinHorizontal(lipgloss.Top, date, name) events = append(events, text) } - if len(m.upcoming) == 0 { - return events - } - - // Next - name := sNextName.Render(m.upcoming[0].Name) - time := sNextTime.Render(m.upcoming[0].Date.Format("02/01") + "\t") - location := sNextPlace.Render("📍 " + m.upcoming[0].Location) + if len(m.upcoming) > 0 { + // Next + date := sOvNextDate.Render(m.upcoming[0].Date.Format("02/01")) + name := sOvNextText.Render(m.upcoming[0].Name) + location := sOvNextLoc.Render("📍 " + m.upcoming[0].Location) - text := lipgloss.JoinVertical(lipgloss.Left, name, location) - text = lipgloss.JoinHorizontal(lipgloss.Top, time, text) + text := lipgloss.JoinVertical(lipgloss.Left, name, location) + text = lipgloss.JoinHorizontal(lipgloss.Top, date, text) - events = append(events, text) + events = append(events, text) + } // Upcoming for i := 1; i < len(m.upcoming); i++ { - time := sUpcomingTime.Render(m.upcoming[i].Date.Format("02/01") + "\t") - name := sUpcomingName.Render(m.upcoming[i].Name) + date := sOvUpcomingDate.Render(m.upcoming[i].Date.Format("02/01")) + name := sOvUpcomingText.Render(m.upcoming[i].Name) text := name if i < 3 { - location := sUpcomingPlace.Render("📍 " + m.upcoming[i].Location) + location := sOvNextLoc.Render("📍 " + m.upcoming[i].Location) text = lipgloss.JoinVertical(lipgloss.Left, name, location) } - text = lipgloss.JoinHorizontal(lipgloss.Top, time, text) + text = lipgloss.JoinHorizontal(lipgloss.Top, date, text) events = append(events, text) } - return events + view := lipgloss.JoinVertical(lipgloss.Left, events...) + + return sOv.Render(view) }