CI / Build & Quality Checks (push) Successful in 1m30s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 6s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
Audit of every rendered time found five families of ad-hoc formatting: the shared Time component + copies of its today/yesterday branch (forwarded header, thread summary, read receipts, device tile, moderation alerts, edit history), locale-default toLocale*String calls that ignored the user's 12/24 h and date-format settings (scheduled tray, reminders, schedule preview, notification snooze, bookmarks, threads list, search cache line, room insights, media gallery), a hard-coded en-US date in the activity log, and three relative-age variants. utils/formatTimestamp.ts now holds the rules — today → time; yesterday / tomorrow → day word + time; last 6 days → weekday + time; older → date + time in dateFormatString — plus autoDate / time / date / dateTime styles, formatDayDivider (full weekday), formatShortAge (room list) and formatRelativeAge (list rows). useTimestampFormatter binds them to the settings. 11 unit tests with an injected 'now'. Visible changes are limited to consistency: 12 h times keep the existing zero-padded hh:mm A; the a11y label and Created-by line use the user's date format instead of a fixed long month. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
60 lines
2.3 KiB
TypeScript
60 lines
2.3 KiB
TypeScript
import { CSSProperties } from 'react';
|
|
import { color as foldsColor, config as foldsConfig } from 'folds';
|
|
import { TimestampPrefs, dayWord, formatDate, formatTime } from './formatTimestamp';
|
|
|
|
const pad = (n: number): string => String(n).padStart(2, '0');
|
|
|
|
// Format a Date as the value string expected by <input type="date"> in the
|
|
// user's LOCAL timezone. (toISOString would shift to UTC and can land on the
|
|
// wrong calendar day.)
|
|
export function toLocalDate(date: Date): string {
|
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
}
|
|
|
|
// Format a Date as the value string expected by <input type="time"> (local, HH:mm).
|
|
export function toLocalTime(date: Date): string {
|
|
return `${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
}
|
|
|
|
// Parse the local date + time <input> values back into a Date. Returns null when
|
|
// either value is missing or the combination is invalid (e.g. a partial entry).
|
|
export function parseLocalDateTime(dateValue: string, timeValue: string): Date | null {
|
|
if (!dateValue || !timeValue) return null;
|
|
const dt = new Date(`${dateValue}T${timeValue}:00`);
|
|
return Number.isNaN(dt.getTime()) ? null : dt;
|
|
}
|
|
|
|
// Human-friendly absolute time for scheduled things: "Today at 03:00 PM",
|
|
// "Tomorrow at 09:00 AM", "Mon at 09:00", or "12 Jan 2026 at 09:00" — the
|
|
// shared day-word rules and the user's clock/date preferences (#139). `now` is
|
|
// injectable so the relative-day logic is testable.
|
|
export function formatFriendlyDateTime(
|
|
ts: number,
|
|
prefs: TimestampPrefs,
|
|
now: number = Date.now(),
|
|
): string {
|
|
const day = dayWord(ts, now) ?? formatDate(ts, prefs);
|
|
return `${day} at ${formatTime(ts, prefs)}`;
|
|
}
|
|
|
|
// Shared style for date/time <input>s — matches the app's surface tokens and
|
|
// hints a dark-mode calendar/clock popup via colorScheme.
|
|
export function pickerInputStyle(
|
|
c: typeof foldsColor = foldsColor,
|
|
cfg: typeof foldsConfig = foldsConfig,
|
|
): CSSProperties {
|
|
return {
|
|
background: c.SurfaceVariant.Container,
|
|
color: c.SurfaceVariant.OnContainer,
|
|
border: `${cfg.borderWidth.B300} solid ${c.SurfaceVariant.ContainerLine}`,
|
|
borderRadius: cfg.radii.R300,
|
|
padding: `${cfg.space.S200} ${cfg.space.S300}`,
|
|
fontSize: '0.875rem',
|
|
width: '100%',
|
|
boxSizing: 'border-box',
|
|
outline: 'none',
|
|
fontFamily: 'inherit',
|
|
colorScheme: 'dark',
|
|
};
|
|
}
|