77 lines
2.8 KiB
TypeScript
77 lines
2.8 KiB
TypeScript
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { EventLogRow, formatSolveDateTime } from './scoreboard.pure';
|
|
|
|
@Component({
|
|
selector: 'app-scoreboard-event-log',
|
|
standalone: true,
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
imports: [CommonModule],
|
|
styles: [`
|
|
:host { display: block; }
|
|
.empty { padding: 32px; text-align: center; opacity: 0.7; }
|
|
ol {
|
|
list-style: none; padding: 0; margin: 0;
|
|
display: flex; flex-direction: column; gap: 6px;
|
|
max-height: 70vh; overflow: auto;
|
|
}
|
|
li {
|
|
display: flex; align-items: center; gap: 12px;
|
|
padding: 8px 10px;
|
|
background: var(--color-surface, #1c1f26);
|
|
border: 1px solid var(--color-border, #2a2f3a);
|
|
border-radius: var(--radius-sm, 4px);
|
|
font-size: 13px;
|
|
}
|
|
.icon { font-size: 18px; min-width: 22px; text-align: center; }
|
|
.icon-gold { color: #d4a017; }
|
|
.icon-silver { color: #9aa3b0; }
|
|
.icon-bronze { color: #b87333; }
|
|
.icon-check { color: var(--color-success, #22c55e); }
|
|
.time { opacity: 0.7; font-variant-numeric: tabular-nums; min-width: 170px; }
|
|
.who { font-weight: 600; min-width: 120px; }
|
|
.what { flex: 1; min-width: 0; }
|
|
.abbrev { opacity: 0.65; margin-right: 6px; font-size: 11px; }
|
|
.pts { font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
`],
|
|
template: `
|
|
<ng-container *ngIf="rows?.length; else empty">
|
|
<ol data-testid="scoreboard-event-log">
|
|
<li *ngFor="let r of rows; trackBy: trackBySolve" [attr.data-testid]="'event-log-row-' + r.solveId">
|
|
<span [class]="iconClass(r)" class="icon" aria-hidden="true">{{ icon(r) }}</span>
|
|
<span class="time">{{ format(r.awardedAtUtc) }}</span>
|
|
<span class="who">{{ r.playerName }}</span>
|
|
<span class="what">
|
|
<span class="abbrev" *ngIf="r.categoryAbbreviation">{{ r.categoryAbbreviation }}</span>
|
|
{{ r.challengeName }}
|
|
</span>
|
|
<span class="pts">+{{ r.awardedPoints }}</span>
|
|
</li>
|
|
</ol>
|
|
</ng-container>
|
|
<ng-template #empty>
|
|
<p class="empty" data-testid="event-log-empty">No solves yet</p>
|
|
</ng-template>
|
|
`,
|
|
})
|
|
export class EventLogComponent {
|
|
@Input() rows: EventLogRow[] | null = [];
|
|
|
|
format = formatSolveDateTime;
|
|
|
|
icon(r: EventLogRow): string {
|
|
if (r.position === 1) return '★';
|
|
if (r.position === 2) return '★';
|
|
if (r.position === 3) return '★';
|
|
return '✓';
|
|
}
|
|
|
|
iconClass(r: EventLogRow): string {
|
|
if (r.position === 1) return 'icon-gold';
|
|
if (r.position === 2) return 'icon-silver';
|
|
if (r.position === 3) return 'icon-bronze';
|
|
return 'icon-check';
|
|
}
|
|
|
|
trackBySolve = (_: number, r: EventLogRow) => r.solveId || `${r.playerId}|${r.challengeId}|${r.awardedAtUtc}`;
|
|
} |