Implements the activity-stats change (specs/activity-stats): - gpx: `movingTime(tracks)` — moving seconds from trackpoint timestamps, excluding stationary spans + long gaps; null when no timestamps. - stats.ts: pure formatters (distance/elevation/duration/speed/pace), sport-aware `deriveRate` (pace for foot sports, speed otherwise, speed default), and `activityStatItems` encoding the canonical order (distance · time · [moving] · pace/speed · ascent · descent; compact subset). - StatRow: one shared presentational component (size sm/lg), adopted on the activity detail (full set; loader derives moving time), route detail (distance/ascent/descent), feed card + profile list (compact). - i18n: journal.stats.* in en + de. Tests: movingTime (stationary/gap exclusion, moving ≤ elapsed), deriveRate, formatters, activityStatItems ordering + compact, StatRow render (jsdom). typecheck + lint + unit (gpx 63, journal 311) green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
34 lines
1,010 B
TypeScript
34 lines
1,010 B
TypeScript
import type { StatItem } from "~/lib/stats";
|
|
|
|
/**
|
|
* The one shared headline-stat presentation. Surfaces pass an ordered list of
|
|
* {value, label} items (built via `activityStatItems`); the component never
|
|
* fetches or formats. `size="lg"` is the detail-page treatment; the default
|
|
* compact size is for feed cards and the profile list.
|
|
*/
|
|
export function StatRow({
|
|
items,
|
|
size = "sm",
|
|
className,
|
|
}: {
|
|
items: StatItem[];
|
|
size?: "sm" | "lg";
|
|
className?: string;
|
|
}) {
|
|
if (items.length === 0) return null;
|
|
const valueCls =
|
|
size === "lg"
|
|
? "text-2xl font-bold text-gray-900"
|
|
: "text-sm font-semibold text-gray-900";
|
|
const gap = size === "lg" ? "gap-6" : "gap-x-4 gap-y-1";
|
|
return (
|
|
<dl className={`flex flex-wrap ${gap}${className ? ` ${className}` : ""}`}>
|
|
{items.map((it) => (
|
|
<div key={it.label}>
|
|
<dd className={valueCls}>{it.value}</dd>
|
|
<dt className="text-xs text-gray-500">{it.label}</dt>
|
|
</div>
|
|
))}
|
|
</dl>
|
|
);
|
|
}
|