import { Component, Input } from '@angular/core'; @Component({ selector: 'vsp-circular-progress', template: `
{{ display }}
`, }) export class VspCircularProgress { @Input() value = 0; @Input() size = 76; @Input() thickness = 7; @Input() color = 'var(--accent)'; @Input() label?: string; get r(): number { return (this.size - this.thickness) / 2; } get circ(): number { return 2 * Math.PI * this.r; } get offset(): number { return this.circ * (1 - Math.min(100, this.value) / 100); } get display(): string { return this.label ?? `${Math.round(this.value)}%`; } } @Component({ selector: 'vsp-stat', template: `
{{ label }}
{{ value }} @if (delta != null) { {{ delta }} }
`, }) export class VspStat { @Input() label?: string; @Input() value?: string; @Input() delta?: string; @Input() deltaDir: 'up' | 'down' = 'up'; @Input() tone = 'var(--accent)'; get deltaCls(): string { return 'badge ' + (this.deltaDir === 'up' ? 'badge-pos' : 'badge-neg'); } get arrow(): string { return this.deltaDir === 'up' ? 'M12 19V5M5 12l7-7 7 7' : 'M12 5v14M5 12l7 7 7-7'; } } export type TimelineTone = 'pos' | 'neg' | 'warn' | 'info'; export interface TimelineItem { title: string; time?: string; body?: string; tone?: TimelineTone; active?: boolean; } const TL_TONE: Record = { pos: 'var(--success)', neg: 'var(--danger)', warn: 'var(--warning)', info: 'var(--accent)', }; @Component({ selector: 'vsp-timeline', template: `
@for (it of items; track $index) {
{{ it.title }} @if (it.time) { {{ it.time }} }
@if (it.body) {
{{ it.body }}
}
}
`, }) export class VspTimeline { @Input() items: TimelineItem[] = []; @Input() orientation: 'vertical' | 'horizontal' = 'vertical'; dotStyle(tone?: TimelineTone): string { if (!tone) return ''; const c = TL_TONE[tone]; return `background:color-mix(in oklab, ${c} 14%, transparent);color:${c};border-color:color-mix(in oklab, ${c} 30%, transparent)`; } } @Component({ selector: 'vsp-description-list', template: `
@for (item of items; track $index; let last = $last) {
{{ item[0] }}
{{ item[1] }}
}
`, }) export class VspDescriptionList { @Input() items: [string, string][] = []; }