feat: home screen and navigation design
This commit is contained in:
1 parent
30a4df47b1
commit
930b836241
24 files changed
+1774
-19
No files matched your search
@@ -0,0 +1,42 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { formatRelativeDate } from '../relativeDate'
|
||||
|
||||
const now = new Date('2026-08-25T12:00:00Z')
|
||||
|
||||
describe('formatRelativeDate', () => {
|
||||
it('formats under an hour in minutes', () => {
|
||||
expect(formatRelativeDate('2026-08-25T11:45:00Z', now)).toBe('15 minutes ago')
|
||||
})
|
||||
|
||||
it('clamps a sub-minute difference to "1 minute ago"', () => {
|
||||
expect(formatRelativeDate('2026-08-25T11:59:45Z', now)).toBe('1 minute ago')
|
||||
})
|
||||
|
||||
it('uses the singular for exactly one minute ago', () => {
|
||||
expect(formatRelativeDate('2026-08-25T11:59:00Z', now)).toBe('1 minute ago')
|
||||
})
|
||||
|
||||
it('formats under a day in hours', () => {
|
||||
expect(formatRelativeDate('2026-08-25T10:00:00Z', now)).toBe('2 hours ago')
|
||||
})
|
||||
|
||||
it('uses the singular for exactly one hour ago', () => {
|
||||
expect(formatRelativeDate('2026-08-25T11:00:00Z', now)).toBe('1 hour ago')
|
||||
})
|
||||
|
||||
it('formats exactly one day back as Yesterday', () => {
|
||||
expect(formatRelativeDate('2026-08-24T11:00:00Z', now)).toBe('Yesterday')
|
||||
})
|
||||
|
||||
it('formats within the week in days', () => {
|
||||
expect(formatRelativeDate('2026-08-22T12:00:00Z', now)).toBe('3 days ago')
|
||||
})
|
||||
|
||||
it('formats exactly 7 days ago as an absolute date, not "7 days ago"', () => {
|
||||
expect(formatRelativeDate('2026-08-18T12:00:00Z', now)).toBe('18 Aug 2026')
|
||||
})
|
||||
|
||||
it('formats a week or more ago as an absolute date', () => {
|
||||
expect(formatRelativeDate('2026-08-10T12:00:00Z', now)).toBe('10 Aug 2026')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,45 @@
|
||||
const MINUTE_MS = 60 * 1000
|
||||
const HOUR_MS = 60 * MINUTE_MS
|
||||
const DAY_MS = 24 * HOUR_MS
|
||||
const RELATIVE_CUTOFF_DAYS = 7
|
||||
|
||||
const MONTH_NAMES = [
|
||||
'Jan',
|
||||
'Feb',
|
||||
'Mar',
|
||||
'Apr',
|
||||
'May',
|
||||
'Jun',
|
||||
'Jul',
|
||||
'Aug',
|
||||
'Sep',
|
||||
'Oct',
|
||||
'Nov',
|
||||
'Dec',
|
||||
]
|
||||
|
||||
function formatAbsoluteDate(date: Date) {
|
||||
return `${date.getDate()} ${MONTH_NAMES[date.getMonth()]} ${date.getFullYear()}`
|
||||
}
|
||||
|
||||
export function formatRelativeDate(iso: string, now: Date = new Date()) {
|
||||
const date = new Date(iso)
|
||||
const diffMs = now.getTime() - date.getTime()
|
||||
|
||||
if (diffMs < HOUR_MS) {
|
||||
const minutes = Math.max(1, Math.floor(diffMs / MINUTE_MS))
|
||||
return minutes === 1 ? '1 minute ago' : `${minutes} minutes ago`
|
||||
}
|
||||
if (diffMs < DAY_MS) {
|
||||
const hours = Math.floor(diffMs / HOUR_MS)
|
||||
return hours === 1 ? '1 hour ago' : `${hours} hours ago`
|
||||
}
|
||||
const days = Math.floor(diffMs / DAY_MS)
|
||||
if (days === 1) {
|
||||
return 'Yesterday'
|
||||
}
|
||||
if (days < RELATIVE_CUTOFF_DAYS) {
|
||||
return `${days} days ago`
|
||||
}
|
||||
return formatAbsoluteDate(date)
|
||||
}
|
||||
Reference in new issue
Block a user