172 lines
4.2 KiB
Go
172 lines
4.2 KiB
Go
package tui
|
|
|
|
import (
|
|
"time"
|
|
|
|
"charm.land/lipgloss/v2"
|
|
)
|
|
|
|
// TimestampConfig holds configuration for message timestamps.
|
|
type TimestampConfig struct {
|
|
Enabled bool
|
|
Format string // "time", "relative", "both"
|
|
Position string // "left", "right"
|
|
MaxAge time.Duration // For relative timestamps
|
|
}
|
|
|
|
// DefaultTimestampConfig returns default configuration.
|
|
func DefaultTimestampConfig() TimestampConfig {
|
|
return TimestampConfig{
|
|
Enabled: false,
|
|
Format: "time",
|
|
Position: "left",
|
|
MaxAge: 24 * time.Hour,
|
|
}
|
|
}
|
|
|
|
// TimestampStyles holds styling for timestamps.
|
|
type TimestampStyles struct {
|
|
Time lipgloss.Style
|
|
Relative lipgloss.Style
|
|
Divider lipgloss.Style
|
|
}
|
|
|
|
// DefaultTimestampStyles returns default styles.
|
|
func DefaultTimestampStyles(isDark bool) TimestampStyles {
|
|
if isDark {
|
|
return TimestampStyles{
|
|
Time: lipgloss.NewStyle().Foreground(lipgloss.Color("#4c566a")),
|
|
Relative: lipgloss.NewStyle().Foreground(lipgloss.Color("#5e81ac")),
|
|
Divider: lipgloss.NewStyle().Foreground(lipgloss.Color("#3b4252")),
|
|
}
|
|
}
|
|
return TimestampStyles{
|
|
Time: lipgloss.NewStyle().Foreground(lipgloss.Color("#9ca0a8")),
|
|
Relative: lipgloss.NewStyle().Foreground(lipgloss.Color("#5e81ac")),
|
|
Divider: lipgloss.NewStyle().Foreground(lipgloss.Color("#d8dee9")),
|
|
}
|
|
}
|
|
|
|
// TimestampHelper provides utilities for rendering timestamps.
|
|
type TimestampHelper struct {
|
|
config TimestampConfig
|
|
styles TimestampStyles
|
|
nowFunc func() time.Time
|
|
}
|
|
|
|
// NewTimestampHelper creates a new timestamp helper.
|
|
func NewTimestampHelper(config TimestampConfig, isDark bool) *TimestampHelper {
|
|
return &TimestampHelper{
|
|
config: config,
|
|
styles: DefaultTimestampStyles(isDark),
|
|
nowFunc: time.Now,
|
|
}
|
|
}
|
|
|
|
// SetDark updates theme.
|
|
func (th *TimestampHelper) SetDark(isDark bool) {
|
|
th.styles = DefaultTimestampStyles(isDark)
|
|
}
|
|
|
|
// SetConfig updates the timestamp configuration.
|
|
func (th *TimestampHelper) SetConfig(config TimestampConfig) {
|
|
th.config = config
|
|
}
|
|
|
|
// FormatTime formats a timestamp based on config.
|
|
func (th *TimestampHelper) FormatTime(t time.Time) string {
|
|
if !th.config.Enabled {
|
|
return ""
|
|
}
|
|
|
|
switch th.config.Format {
|
|
case "time":
|
|
return t.Format("15:04")
|
|
case "relative":
|
|
return th.relativeTime(t)
|
|
case "both":
|
|
return t.Format("15:04") + " " + th.relativeTime(t)
|
|
default:
|
|
return t.Format("15:04")
|
|
}
|
|
}
|
|
|
|
// relativeTime returns a human-readable relative time string.
|
|
func (th *TimestampHelper) relativeTime(t time.Time) string {
|
|
now := th.nowFunc()
|
|
diff := now.Sub(t)
|
|
|
|
if diff < time.Minute {
|
|
return "just now"
|
|
}
|
|
if diff < time.Hour {
|
|
mins := int(diff.Minutes())
|
|
if mins == 1 {
|
|
return "1m ago"
|
|
}
|
|
return formatInt(mins) + "m ago"
|
|
}
|
|
if diff < 24*time.Hour {
|
|
hours := int(diff.Hours())
|
|
if hours == 1 {
|
|
return "1h ago"
|
|
}
|
|
return formatInt(hours) + "h ago"
|
|
}
|
|
if diff < 7*24*time.Hour {
|
|
days := int(diff.Hours() / 24)
|
|
if days == 1 {
|
|
return "1d ago"
|
|
}
|
|
return formatInt(days) + "d ago"
|
|
}
|
|
|
|
// Older dates - show date
|
|
return t.Format("Jan 2")
|
|
}
|
|
|
|
// formatInt formats an integer without allocation.
|
|
func formatInt(n int) string {
|
|
if n < 10 {
|
|
return string(rune('0' + n))
|
|
}
|
|
// Simple implementation for common cases
|
|
switch n {
|
|
case 10:
|
|
return "10"
|
|
case 11:
|
|
return "11"
|
|
case 12:
|
|
return "12"
|
|
case 13:
|
|
return "13"
|
|
case 14:
|
|
return "14"
|
|
case 15:
|
|
return "15"
|
|
case 16:
|
|
return "16"
|
|
case 17:
|
|
return "17"
|
|
case 18:
|
|
return "18"
|
|
case 19:
|
|
return "19"
|
|
case 20:
|
|
return "20"
|
|
default:
|
|
// Fallback for larger numbers
|
|
if n < 100 {
|
|
tens := n / 10
|
|
ones := n % 10
|
|
return string(rune('0'+tens)) + string(rune('0'+ones))
|
|
}
|
|
return string(rune('0' + n/100))
|
|
}
|
|
}
|
|
|
|
// MessageTime stores the timestamp for a chat message.
|
|
type MessageTime struct {
|
|
Time time.Time
|
|
}
|