feat: NCWF-5/6/7/8/9 chess analysis page and engine integration

- NCWF-5: scaffold /analysis route with ChessBoard viewer and navigation
- NCWF-6: FEN / PGN / Game-ID input form with depth selector
- NCWF-7: extend GameApiService with analyzePosition(); add AnalysisService
  with game-wide annotation pipeline; proxy /api/analysis -> :8087
- NCWF-8: EvalTimelineComponent — SVG win-chance chart per ply
- NCWF-9: AnnotatedMoveListComponent — quality labels (!! ! ?! ? ??)
  derived from win-chance delta

Also fix pre-existing app.spec.ts failure (missing provideHttpClient).
Apply project-wide prettier formatting pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Janis Eccarius
2026-06-10 15:55:14 +02:00
parent ae952d70b0
commit 8e2afb93f3
115 changed files with 6134 additions and 2378 deletions
@@ -1,38 +1,50 @@
<div class="challenge-notification" [class.error]="!!errorMessage">
<div class="notification-header">
<div class="notification-title">
<span class="badge">CHALLENGE</span>
<span class="title">{{ getCreatedByDisplay() }} challenged you!</span>
</div>
<button type="button" class="close-btn" (click)="onClose()"
[disabled]="acceptingChallenge || decliningChallenge">
×
</button>
<div class="notification-header">
<div class="notification-title">
<span class="badge">CHALLENGE</span>
<span class="title">{{ getCreatedByDisplay() }} challenged you!</span>
</div>
<button
type="button"
class="close-btn"
(click)="onClose()"
[disabled]="acceptingChallenge || decliningChallenge"
>
×
</button>
</div>
<div class="notification-content">
<div class="time-control">
<span class="label">Time Control:</span>
<span class="value">{{ getTimeControlDisplay() }}</span>
</div>
<div class="notification-content">
<div class="time-control">
<span class="label">Time Control:</span>
<span class="value">{{ getTimeControlDisplay() }}</span>
</div>
<div class="expiration">
<span class="label">{{ getExpirationInfo() }}</span>
</div>
<div *ngIf="errorMessage" class="error-message">
{{ errorMessage }}
</div>
<div class="notification-actions">
<button type="button" class="btn btn-decline" (click)="onDecline()"
[disabled]="acceptingChallenge || decliningChallenge">
{{ decliningChallenge ? 'Declining...' : 'Decline' }}
</button>
<button type="button" class="btn btn-accept" (click)="onAccept()"
[disabled]="acceptingChallenge || decliningChallenge">
{{ acceptingChallenge ? 'Accepting...' : 'Accept' }}
</button>
</div>
<div class="expiration">
<span class="label">{{ getExpirationInfo() }}</span>
</div>
</div>
<div *ngIf="errorMessage" class="error-message">
{{ errorMessage }}
</div>
<div class="notification-actions">
<button
type="button"
class="btn btn-decline"
(click)="onDecline()"
[disabled]="acceptingChallenge || decliningChallenge"
>
{{ decliningChallenge ? 'Declining...' : 'Decline' }}
</button>
<button
type="button"
class="btn btn-accept"
(click)="onAccept()"
[disabled]="acceptingChallenge || decliningChallenge"
>
{{ acceptingChallenge ? 'Accepting...' : 'Accept' }}
</button>
</div>
</div>
</div>