Skip to content

Commit 6bbe6c9

Browse files
authored
feat: From in inbox view (#268)
1 parent d8b7ddb commit 6bbe6c9

2 files changed

Lines changed: 51 additions & 12 deletions

File tree

fetcher/fetcher.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ type Folder struct {
5959
Attributes []string
6060
}
6161

62+
// formatAddress returns "Name <email>" when a PersonalName is present,
63+
// otherwise just "email".
64+
func formatAddress(addr *imap.Address) string {
65+
email := addr.Address()
66+
if addr.PersonalName != "" {
67+
return addr.PersonalName + " <" + email + ">"
68+
}
69+
return email
70+
}
71+
6272
func decodePart(reader io.Reader, header mail.PartHeader) (string, error) {
6373
mediaType, params, err := mime.ParseMediaType(header.Get("Content-Type"))
6474
if err != nil {
@@ -275,7 +285,7 @@ func FetchMailboxEmails(account *config.Account, mailbox string, limit, offset u
275285

276286
var fromAddr string
277287
if len(msg.Envelope.From) > 0 {
278-
fromAddr = msg.Envelope.From[0].Address()
288+
fromAddr = formatAddress(msg.Envelope.From[0])
279289
}
280290

281291
var toAddrList []string
@@ -1079,7 +1089,7 @@ func FetchArchiveEmails(account *config.Account, limit, offset uint32) ([]Email,
10791089

10801090
var fromAddr string
10811091
if len(msg.Envelope.From) > 0 {
1082-
fromAddr = msg.Envelope.From[0].Address()
1092+
fromAddr = formatAddress(msg.Envelope.From[0])
10831093
}
10841094

10851095
var toAddrList []string

tui/inbox.go

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ var (
2323
tabBarStyle = lipgloss.NewStyle().BorderStyle(lipgloss.NormalBorder()).BorderBottom(true).PaddingBottom(1).MarginBottom(1)
2424
)
2525

26-
var dateStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("243"))
26+
var dateStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("243"))
27+
var senderStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("250")).Bold(true)
2728

2829
type item struct {
2930
title, desc string
@@ -49,37 +50,52 @@ func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list
4950
return
5051
}
5152

52-
str := fmt.Sprintf("%d. %s", index+1, i.title)
53+
prefix := fmt.Sprintf("%d. ", index+1)
54+
sender := parseSenderName(i.desc)
55+
styledSender := senderStyle.Render(sender)
56+
separator := " · "
5357

54-
// For "ALL" view, show account indicator
58+
// For "ALL" view, show account indicator instead of number
5559
if i.accountEmail != "" {
56-
str = fmt.Sprintf("%d. [%s] %s", index+1, truncateEmail(i.accountEmail), i.title)
60+
prefix = fmt.Sprintf("%d. [%s] ", index+1, truncateEmail(i.accountEmail))
5761
}
5862

5963
// Format and right-align date
6064
dateStr := formatRelativeDate(i.date)
6165
styledDate := dateStyle.Render(dateStr)
6266
dateWidth := lipgloss.Width(styledDate)
6367

64-
// Truncate the left part to fit within the available width
6568
listWidth := m.Width()
6669
isSelected := index == m.Index()
6770
cursorWidth := 0
6871
if isSelected {
6972
cursorWidth = 2 // "> " prefix
7073
}
74+
75+
// Available width for the whole left side (prefix + sender + separator + subject)
7176
maxLeft := listWidth - dateWidth - 2 - cursorWidth // 2 for spacing
7277
if maxLeft < 10 {
7378
maxLeft = 10
7479
}
75-
if lipgloss.Width(str) > maxLeft {
76-
// Truncate with ellipsis
77-
for lipgloss.Width(str) > maxLeft-1 && len(str) > 0 {
78-
str = str[:len(str)-1]
80+
81+
prefixWidth := lipgloss.Width(prefix)
82+
senderWidth := lipgloss.Width(styledSender)
83+
sepWidth := len(separator)
84+
subjectBudget := maxLeft - prefixWidth - senderWidth - sepWidth
85+
86+
subject := i.title
87+
if subjectBudget < 4 {
88+
subjectBudget = 4
89+
}
90+
if lipgloss.Width(subject) > subjectBudget {
91+
for lipgloss.Width(subject) > subjectBudget-1 && len(subject) > 0 {
92+
subject = subject[:len(subject)-1]
7993
}
80-
str += "…"
94+
subject += "…"
8195
}
8296

97+
str := prefix + styledSender + separator + subject
98+
8399
// Pad to push date to the right
84100
padding := listWidth - lipgloss.Width(str) - dateWidth - cursorWidth
85101
if padding < 1 {
@@ -134,6 +150,19 @@ func formatRelativeDate(t time.Time) string {
134150
}
135151
}
136152

153+
// parseSenderName extracts the display name from a "Name <email>" string,
154+
// falling back to the local part of the email address.
155+
func parseSenderName(from string) string {
156+
if idx := strings.Index(from, " <"); idx > 0 {
157+
return strings.TrimSpace(from[:idx])
158+
}
159+
// No display name — use local part of email
160+
if idx := strings.Index(from, "@"); idx > 0 {
161+
return from[:idx]
162+
}
163+
return from
164+
}
165+
137166
// truncateEmail shortens an email for display
138167
func truncateEmail(email string) string {
139168
parts := strings.Split(email, "@")

0 commit comments

Comments
 (0)