fix: show date in timestamps; fix history divider appearing immediately
- MessagePane: show date in timestamps (Yesterday/MMM D) for messages not from today; divider now appears at the top of history on load rather than waiting for a live message to create the boundary - TUI: same date-aware timestamp formatting (Yesterday / Jan 2) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -383,7 +383,7 @@ func (m model) refreshViewport() model {
|
|||||||
w := m.vpContentWidth()
|
w := m.vpContentWidth()
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
for _, e := range m.messages[room] {
|
for _, e := range m.messages[room] {
|
||||||
ts := styleMsgTime.Render(e.at.Format("15:04"))
|
ts := styleMsgTime.Render(formatMsgTime(e.at))
|
||||||
var from string
|
var from string
|
||||||
if e.fromMe {
|
if e.fromMe {
|
||||||
from = styleMsgMe.Render(e.from)
|
from = styleMsgMe.Render(e.from)
|
||||||
@@ -614,6 +614,17 @@ func filterIDs(ids []proto.PeerID, remove proto.PeerID) []proto.PeerID {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formatMsgTime(t time.Time) string {
|
||||||
|
now := time.Now()
|
||||||
|
if t.Year() == now.Year() && t.YearDay() == now.YearDay() {
|
||||||
|
return t.Format("15:04")
|
||||||
|
}
|
||||||
|
if t.Year() == now.Year() && t.YearDay() == now.YearDay()-1 {
|
||||||
|
return "Yesterday " + t.Format("15:04")
|
||||||
|
}
|
||||||
|
return t.Format("Jan 2 15:04")
|
||||||
|
}
|
||||||
|
|
||||||
func min(a, b int) int {
|
func min(a, b int) int {
|
||||||
if a < b {
|
if a < b {
|
||||||
return a
|
return a
|
||||||
|
|||||||
@@ -1,6 +1,18 @@
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { useWaste } from '../store'
|
import { useWaste } from '../store'
|
||||||
|
|
||||||
|
const today = new Date()
|
||||||
|
today.setHours(0, 0, 0, 0)
|
||||||
|
const todayMs = today.getTime()
|
||||||
|
const yesterdayMs = todayMs - 86400000
|
||||||
|
|
||||||
|
function formatTs(ts: number): string {
|
||||||
|
const time = new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false })
|
||||||
|
if (ts >= todayMs) return time
|
||||||
|
if (ts >= yesterdayMs) return `Yesterday ${time}`
|
||||||
|
return new Date(ts).toLocaleDateString([], { month: 'short', day: 'numeric' }) + ' ' + time
|
||||||
|
}
|
||||||
|
|
||||||
export function MessagePane() {
|
export function MessagePane() {
|
||||||
const { messages, historyCutoff, activeRoom, activeNetworkId, localPeer, connectedPeers, send } = useWaste()
|
const { messages, historyCutoff, activeRoom, activeNetworkId, localPeer, connectedPeers, send } = useWaste()
|
||||||
const [draft, setDraft] = useState('')
|
const [draft, setDraft] = useState('')
|
||||||
@@ -8,6 +20,16 @@ export function MessagePane() {
|
|||||||
const roomMessages = messages[activeRoom] ?? []
|
const roomMessages = messages[activeRoom] ?? []
|
||||||
const cutoff = historyCutoff[activeRoom] ?? 0
|
const cutoff = historyCutoff[activeRoom] ?? 0
|
||||||
|
|
||||||
|
// Find the index of the first live message (ts > cutoff).
|
||||||
|
// The divider appears just before this index, or at the top if all are history.
|
||||||
|
const firstLiveIdx = cutoff > 0
|
||||||
|
? roomMessages.findIndex(m => m.ts > cutoff)
|
||||||
|
: -1
|
||||||
|
// If all messages are history (no live yet), put divider at the start.
|
||||||
|
const dividerIdx = cutoff > 0
|
||||||
|
? (firstLiveIdx === -1 ? 0 : firstLiveIdx)
|
||||||
|
: -1
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
bottomRef.current?.scrollIntoView({ behavior: 'smooth' })
|
bottomRef.current?.scrollIntoView({ behavior: 'smooth' })
|
||||||
}, [roomMessages.length])
|
}, [roomMessages.length])
|
||||||
@@ -43,20 +65,20 @@ export function MessagePane() {
|
|||||||
<div className="message-pane-header">{roomLabel}</div>
|
<div className="message-pane-header">{roomLabel}</div>
|
||||||
|
|
||||||
<div className="messages">
|
<div className="messages">
|
||||||
|
{dividerIdx === 0 && (
|
||||||
|
<div className="history-divider"><span>earlier messages</span></div>
|
||||||
|
)}
|
||||||
{roomMessages.map((msg, i) => {
|
{roomMessages.map((msg, i) => {
|
||||||
const mine = msg.from === localPeer?.id
|
const mine = msg.from === localPeer?.id
|
||||||
const alias = aliasFor(msg.from)
|
const alias = aliasFor(String(msg.from))
|
||||||
const time = new Date(msg.ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false })
|
const ts = formatTs(msg.ts)
|
||||||
const showDivider = cutoff > 0 && i > 0 && roomMessages[i - 1].ts <= cutoff && msg.ts > cutoff
|
|
||||||
return (
|
return (
|
||||||
<div key={msg.mid ?? i}>
|
<div key={msg.mid ?? i}>
|
||||||
{showDivider && (
|
{i === dividerIdx && dividerIdx > 0 && (
|
||||||
<div className="history-divider">
|
<div className="history-divider"><span>earlier messages</span></div>
|
||||||
<span>earlier messages</span>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
<div className={`message ${mine ? 'mine' : ''}`}>
|
<div className={`message ${mine ? 'mine' : ''}`}>
|
||||||
<span className="message-ts">{time}</span>
|
<span className="message-ts">{ts}</span>
|
||||||
<span className="message-alias">{alias}</span>
|
<span className="message-alias">{alias}</span>
|
||||||
<span className="message-text">{msg.text}</span>
|
<span className="message-text">{msg.text}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user