6d5d74b9bb
Tracks Path of Exile 2 currency values via poe.ninja's public economy API, mirroring the existing Weather/Stocks sidebar modules. Always follows the current challenge league (auto-detected, no admin picker). Admin browses and picks currencies from a live list rather than typing symbols, since currency ids are opaque. Change % is a 7-day window, labeled accordingly to avoid the same interval ambiguity Stocks had. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014c1L8ghNBFjfiH64UMViP8
47 lines
1.8 KiB
TypeScript
47 lines
1.8 KiB
TypeScript
export function timeAgo(iso: string): string {
|
|
const diffMs = Date.now() - new Date(iso).getTime();
|
|
const mins = Math.round(diffMs / 60000);
|
|
if (mins < 60) return `${mins}m ago`;
|
|
const hours = Math.round(mins / 60);
|
|
if (hours < 24) return `${hours}h ago`;
|
|
const days = Math.round(hours / 24);
|
|
return `${days}d ago`;
|
|
}
|
|
|
|
/** "05/31/2025 - 05:34 PM" — the original feed publish time (or synthesis time for merged articles), alongside the relative timeAgo(). */
|
|
export function exactTime(iso: string): string {
|
|
const d = new Date(iso);
|
|
const mm = String(d.getMonth() + 1).padStart(2, '0');
|
|
const dd = String(d.getDate()).padStart(2, '0');
|
|
const yyyy = d.getFullYear();
|
|
let hours = d.getHours();
|
|
const minutes = String(d.getMinutes()).padStart(2, '0');
|
|
const ampm = hours >= 12 ? 'PM' : 'AM';
|
|
hours = hours % 12 || 12;
|
|
return `${mm}/${dd}/${yyyy} - ${String(hours).padStart(2, '0')}:${minutes} ${ampm}`;
|
|
}
|
|
|
|
export function slugify(name: string): string {
|
|
return name
|
|
.toLowerCase()
|
|
.trim()
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.replace(/(^-|-$)/g, '');
|
|
}
|
|
|
|
/** Roughly the first N sentences of a plain-text body — enough to give a sense of the article without reading it. */
|
|
export function excerpt(body: string, sentenceCount = 2): string {
|
|
const singleLine = body.replace(/\s+/g, ' ').trim();
|
|
const sentences = singleLine.match(/[^.!?]+[.!?]+/g) ?? [singleLine];
|
|
return sentences.slice(0, sentenceCount).join(' ').trim();
|
|
}
|
|
|
|
/** PoE currency values span many orders of magnitude (e.g. 0.00002749 to 4856) — a fixed decimal count alone reads badly across that range. */
|
|
export function formatPoeValue(value: number): string {
|
|
if (value === 0) return '0';
|
|
if (value >= 100) return value.toFixed(0);
|
|
if (value >= 1) return value.toFixed(2);
|
|
if (value >= 0.01) return value.toFixed(3);
|
|
return value.toPrecision(2);
|
|
}
|