AI Implementation feature(863): Challenges Page and Challenge Solve Modal (#45)
This commit was merged in pull request #45.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { BoardCard } from './challenges.pure';
|
||||
|
||||
@Component({
|
||||
selector: 'app-challenge-card',
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule],
|
||||
styles: [`
|
||||
:host { display: block; }
|
||||
.card {
|
||||
display: flex; flex-direction: column; gap: 6px;
|
||||
padding: 10px 12px; border: 1px solid var(--color-border, #2a2f3a);
|
||||
border-radius: var(--radius-sm, 4px); background: var(--color-surface, #1c1f26);
|
||||
cursor: pointer; transition: transform 0.1s ease;
|
||||
min-height: 96px;
|
||||
}
|
||||
.card:hover { transform: translateY(-1px); border-color: var(--color-primary, #3b82f6); }
|
||||
.card.solved { border-color: var(--color-success, #22c55e); }
|
||||
.card-head { display: flex; align-items: center; gap: 8px; }
|
||||
.icon { width: 28px; height: 28px; object-fit: contain; }
|
||||
.name { font-weight: 600; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.check { color: var(--color-success, #22c55e); font-size: 18px; }
|
||||
.meta { display: flex; gap: 8px; font-size: 12px; opacity: 0.85; align-items: center; }
|
||||
.points { font-weight: 600; }
|
||||
.diff {
|
||||
display: inline-block; padding: 1px 6px; border-radius: 999px; font-size: 10px; letter-spacing: 0.04em;
|
||||
}
|
||||
.diff-LOW { background: rgba(34,197,94,0.18); color: #16a34a; }
|
||||
.diff-MEDIUM { background: rgba(234,179,8,0.18); color: #ca8a04; }
|
||||
.diff-HIGH { background: rgba(239,68,68,0.18); color: #dc2626; }
|
||||
`],
|
||||
template: `
|
||||
<div
|
||||
class="card"
|
||||
[class.solved]="card.solvedByMe"
|
||||
[attr.data-testid]="'challenge-card-' + card.id"
|
||||
(click)="open.emit(card.id)"
|
||||
>
|
||||
<div class="card-head">
|
||||
<img *ngIf="card.categoryIconPath" class="icon" [src]="card.categoryIconPath" [alt]="card.categoryAbbreviation" />
|
||||
<span class="name">{{ card.name }}</span>
|
||||
<span *ngIf="card.solvedByMe" class="check" aria-label="Solved">✓</span>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<span class="diff" [class]="'diff-' + card.difficulty">{{ card.difficulty }}</span>
|
||||
<span class="points" [attr.data-testid]="'points-' + card.id">{{ card.livePoints }} pts</span>
|
||||
<span>·</span>
|
||||
<span>{{ card.solveCount }} solve<span *ngIf="card.solveCount !== 1">s</span></span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
export class ChallengeCardComponent {
|
||||
@Input({ required: true }) card!: BoardCard;
|
||||
@Output() open = new EventEmitter<string>();
|
||||
}
|
||||
Reference in New Issue
Block a user