From 6fedb05e13063e0d710c00278f0a9fa27341f057 Mon Sep 17 00:00:00 2001 From: drew Date: Tue, 10 Mar 2026 10:10:17 +0400 Subject: [PATCH 1/2] feat: dates in inbox Signed-off-by: drew --- tui/inbox.go | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/tui/inbox.go b/tui/inbox.go index 52ddd15f..7242d526 100644 --- a/tui/inbox.go +++ b/tui/inbox.go @@ -4,6 +4,7 @@ import ( "fmt" "io" "strings" + "time" "charm.land/bubbles/v2/key" "charm.land/bubbles/v2/list" @@ -22,12 +23,15 @@ var ( tabBarStyle = lipgloss.NewStyle().BorderStyle(lipgloss.NormalBorder()).BorderBottom(true).PaddingBottom(1).MarginBottom(1) ) +var dateStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("243")) + type item struct { title, desc string originalIndex int uid uint32 accountID string accountEmail string + date time.Time } func (i item) Title() string { return i.title } @@ -52,6 +56,31 @@ func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list str = fmt.Sprintf("%d. [%s] %s", index+1, truncateEmail(i.accountEmail), i.title) } + // Format and right-align date + dateStr := formatRelativeDate(i.date) + styledDate := dateStyle.Render(dateStr) + dateWidth := lipgloss.Width(styledDate) + + // Truncate the left part to fit within the available width + listWidth := m.Width() + maxLeft := listWidth - dateWidth - 2 // 2 for spacing + if maxLeft < 10 { + maxLeft = 10 + } + if lipgloss.Width(str) > maxLeft { + // Truncate with ellipsis + for lipgloss.Width(str) > maxLeft-1 && len(str) > 0 { + str = str[:len(str)-1] + } + str += "…" + } + + // Pad to push date to the right + padding := listWidth - lipgloss.Width(str) - dateWidth + if padding < 1 { + padding = 1 + } + fn := itemStyle.Render if index == m.Index() { fn = func(s ...string) string { @@ -59,7 +88,45 @@ func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list } } - fmt.Fprint(w, fn(str)) + fmt.Fprint(w, fn(str+strings.Repeat(" ", padding)+styledDate)) +} + +// formatRelativeDate formats a time as relative if within the last week, +// otherwise as an absolute date. +func formatRelativeDate(t time.Time) string { + if t.IsZero() { + return "" + } + now := time.Now() + d := now.Sub(t) + + switch { + case d < time.Minute: + return "just now" + case d < time.Hour: + mins := int(d.Minutes()) + if mins == 1 { + return "1 min ago" + } + return fmt.Sprintf("%d min ago", mins) + case d < 24*time.Hour: + hours := int(d.Hours()) + if hours == 1 { + return "1 hour ago" + } + return fmt.Sprintf("%d hours ago", hours) + case d < 7*24*time.Hour: + days := int(d.Hours() / 24) + if days == 1 { + return "1 day ago" + } + return fmt.Sprintf("%d days ago", days) + default: + if t.Year() == now.Year() { + return t.Format("Jan 02") + } + return t.Format("Jan 02, 2006") + } } // truncateEmail shortens an email for display @@ -205,6 +272,7 @@ func (m *Inbox) updateList() { uid: email.UID, accountID: email.AccountID, accountEmail: accountEmail, + date: email.Date, } } From aec420df35985bb71b4e68e25846494d3031993a Mon Sep 17 00:00:00 2001 From: drew Date: Tue, 10 Mar 2026 10:13:05 +0400 Subject: [PATCH 2/2] fix: dynamic behavior on index selected Signed-off-by: drew --- tui/inbox.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tui/inbox.go b/tui/inbox.go index 7242d526..3791b3f9 100644 --- a/tui/inbox.go +++ b/tui/inbox.go @@ -63,7 +63,12 @@ func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list // Truncate the left part to fit within the available width listWidth := m.Width() - maxLeft := listWidth - dateWidth - 2 // 2 for spacing + isSelected := index == m.Index() + cursorWidth := 0 + if isSelected { + cursorWidth = 2 // "> " prefix + } + maxLeft := listWidth - dateWidth - 2 - cursorWidth // 2 for spacing if maxLeft < 10 { maxLeft = 10 } @@ -76,7 +81,7 @@ func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list } // Pad to push date to the right - padding := listWidth - lipgloss.Width(str) - dateWidth + padding := listWidth - lipgloss.Width(str) - dateWidth - cursorWidth if padding < 1 { padding = 1 }