website refactor
This commit is contained in:
24
apps/website/lib/display-objects/DurationDisplay.ts
Normal file
24
apps/website/lib/display-objects/DurationDisplay.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* DurationDisplay
|
||||
*
|
||||
* Deterministic formatting for time durations.
|
||||
*/
|
||||
|
||||
export class DurationDisplay {
|
||||
/**
|
||||
* Formats milliseconds as "123.45ms".
|
||||
*/
|
||||
static formatMs(ms: number): string {
|
||||
return `${ms.toFixed(2)}ms`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats seconds as "M:SS.mmm".
|
||||
* Example: 65.123 -> "1:05.123"
|
||||
*/
|
||||
static formatSeconds(seconds: number): string {
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainingSeconds = (seconds % 60).toFixed(3);
|
||||
return `${minutes}:${remainingSeconds.padStart(6, '0')}`;
|
||||
}
|
||||
}
|
||||
24
apps/website/lib/display-objects/FinishDisplay.ts
Normal file
24
apps/website/lib/display-objects/FinishDisplay.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* FinishDisplay
|
||||
*
|
||||
* Deterministic formatting for race finish positions.
|
||||
*/
|
||||
|
||||
export class FinishDisplay {
|
||||
/**
|
||||
* Formats a finish position as "P1", "P2", etc.
|
||||
*/
|
||||
static format(position: number | null | undefined): string {
|
||||
if (position === null || position === undefined) return '—';
|
||||
return `P${position.toFixed(0)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an average finish position with one decimal place.
|
||||
* Example: 5.4 -> "P5.4"
|
||||
*/
|
||||
static formatAverage(avg: number | null | undefined): string {
|
||||
if (avg === null || avg === undefined) return '—';
|
||||
return `P${avg.toFixed(1)}`;
|
||||
}
|
||||
}
|
||||
21
apps/website/lib/display-objects/MemoryDisplay.ts
Normal file
21
apps/website/lib/display-objects/MemoryDisplay.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* MemoryDisplay
|
||||
*
|
||||
* Deterministic formatting for memory usage.
|
||||
*/
|
||||
|
||||
export class MemoryDisplay {
|
||||
/**
|
||||
* Formats bytes as "123.4MB".
|
||||
*/
|
||||
static formatMB(bytes: number): string {
|
||||
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats bytes as "123.4KB".
|
||||
*/
|
||||
static formatKB(bytes: number): string {
|
||||
return `${(bytes / 1024).toFixed(1)}KB`;
|
||||
}
|
||||
}
|
||||
@@ -15,4 +15,17 @@ export class NumberDisplay {
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
return parts.join('.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a number in compact form (e.g., 1.2k, 1.5M).
|
||||
*/
|
||||
static formatCompact(value: number): string {
|
||||
if (value >= 1000000) {
|
||||
return `${(value / 1000000).toFixed(1)}M`;
|
||||
}
|
||||
if (value >= 1000) {
|
||||
return `${(value / 1000).toFixed(1)}k`;
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
25
apps/website/lib/display-objects/PercentDisplay.ts
Normal file
25
apps/website/lib/display-objects/PercentDisplay.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* PercentDisplay
|
||||
*
|
||||
* Deterministic formatting for percentages.
|
||||
*/
|
||||
|
||||
export class PercentDisplay {
|
||||
/**
|
||||
* Formats a decimal value as a percentage string.
|
||||
* Example: 0.1234 -> "12.3%"
|
||||
*/
|
||||
static format(value: number | null | undefined): string {
|
||||
if (value === null || value === undefined) return '0.0%';
|
||||
return `${(value * 100).toFixed(1)}%`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a whole number as a percentage string.
|
||||
* Example: 85 -> "85%"
|
||||
*/
|
||||
static formatWhole(value: number | null | undefined): string {
|
||||
if (value === null || value === undefined) return '0%';
|
||||
return `${Math.round(value)}%`;
|
||||
}
|
||||
}
|
||||
44
apps/website/lib/display-objects/StatusDisplay.ts
Normal file
44
apps/website/lib/display-objects/StatusDisplay.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* StatusDisplay
|
||||
*
|
||||
* Deterministic mapping of status codes to human-readable labels.
|
||||
*/
|
||||
|
||||
export class StatusDisplay {
|
||||
/**
|
||||
* Maps transaction status to label.
|
||||
*/
|
||||
static transactionStatus(status: string): string {
|
||||
const map: Record<string, string> = {
|
||||
paid: 'Paid',
|
||||
pending: 'Pending',
|
||||
overdue: 'Overdue',
|
||||
failed: 'Failed',
|
||||
};
|
||||
return map[status] || status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps race status to label.
|
||||
*/
|
||||
static raceStatus(status: string): string {
|
||||
const map: Record<string, string> = {
|
||||
scheduled: 'Scheduled',
|
||||
running: 'Live',
|
||||
completed: 'Completed',
|
||||
};
|
||||
return map[status] || status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps protest status to label.
|
||||
*/
|
||||
static protestStatus(status: string): string {
|
||||
const map: Record<string, string> = {
|
||||
pending: 'Pending',
|
||||
under_review: 'Under Review',
|
||||
resolved: 'Resolved',
|
||||
};
|
||||
return map[status] || status;
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,9 @@ export class WinRateDisplay {
|
||||
const rate = (wins / racesCompleted) * 100;
|
||||
return rate.toFixed(1);
|
||||
}
|
||||
|
||||
static format(rate: number | null | undefined): string {
|
||||
if (rate === null || rate === undefined) return '0.0%';
|
||||
return `${rate.toFixed(1)}%`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user