fix: NCWF-2 bugs and desing fixes (#7)

Co-authored-by: Lala, Shahd <Shahd.Lala@sybit.de>
Reviewed-on: #7
This commit was merged in pull request #7.
This commit is contained in:
2026-05-15 02:16:43 +02:00
parent 70a4debb40
commit c02414ea40
45 changed files with 3167 additions and 1277 deletions
@@ -0,0 +1,94 @@
.moves {
display: grid;
grid-template-columns: 38px 1fr 1fr;
font-family: var(--nc-mono);
font-size: 12px;
max-height: 260px;
overflow-y: auto;
}
.moves-empty {
grid-column: 1 / -1;
padding: 16px;
color: var(--nc-text-dim);
font-size: 12px;
text-align: center;
}
.mv-num {
padding: 6px 12px 6px 10px;
color: var(--nc-text-dim);
text-align: right;
border-right: 1px solid var(--nc-border);
}
.mv {
padding: 6px 10px;
color: var(--nc-text);
cursor: pointer;
transition: background 0.1s, color 0.1s;
}
.mv:hover {
background: rgba(255, 69, 200, 0.06);
color: var(--nc-neon);
}
.mv.current {
background: rgba(255, 69, 200, 0.10);
color: var(--nc-neon);
}
.mv.mv-empty {
color: var(--nc-text-dim);
cursor: default;
}
.mv.mv-empty:hover {
background: transparent;
color: var(--nc-text-dim);
}
.moves-foot {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
border-top: 1px solid var(--nc-border);
}
.moves-nav {
display: flex;
gap: 2px;
}
.icon-btn {
background: transparent;
border: 1px solid transparent;
color: var(--nc-text-muted);
width: 26px;
height: 26px;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: color 0.15s, border-color 0.15s;
}
.icon-btn:hover {
color: var(--nc-neon);
border-color: var(--nc-border);
}
.live-label {
font-family: var(--nc-mono);
font-size: 10px;
color: var(--nc-neon);
letter-spacing: 0.14em;
opacity: 0.8;
}
.moves::-webkit-scrollbar { width: 6px; }
.moves::-webkit-scrollbar-track { background: transparent; }
.moves::-webkit-scrollbar-thumb { background: var(--nc-border-strong); border-radius: 3px; }
.moves::-webkit-scrollbar-thumb:hover { background: var(--nc-neon-soft); }
@@ -0,0 +1,43 @@
<div class="moves" role="list">
@if (movePairs.length === 0) {
<div class="moves-empty">No moves yet.</div>
} @else {
@for (pair of movePairs; track $index) {
<div class="mv-num" role="presentation">{{ $index + 1 }}</div>
<div class="mv" [class.current]="currentWhiteIndex === $index" role="listitem">
{{ pair.white }}
</div>
<div class="mv" [class.current]="currentBlackIndex === $index" [class.mv-empty]="!pair.black" role="listitem">
{{ pair.black ?? '…' }}
</div>
}
}
</div>
<div class="moves-foot">
<div class="moves-nav" role="group" aria-label="Move navigation">
<button class="icon-btn" title="First move" (click)="navigate.emit('first')">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="11 17 6 12 11 7"/><polyline points="18 17 13 12 18 7"/>
</svg>
</button>
<button class="icon-btn" title="Previous move" (click)="navigate.emit('prev')">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="15 18 9 12 15 6"/>
</svg>
</button>
<button class="icon-btn" title="Next move" (click)="navigate.emit('next')">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="9 18 15 12 9 6"/>
</svg>
</button>
<button class="icon-btn" title="Last move" (click)="navigate.emit('last')">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="13 17 18 12 13 7"/><polyline points="6 17 11 12 6 7"/>
</svg>
</button>
</div>
@if (plyCount > 0) {
<span class="live-label">LIVE</span>
}
</div>
@@ -0,0 +1,52 @@
import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
export type MoveNavDirection = 'first' | 'prev' | 'next' | 'last';
interface MovePair {
white: string;
black: string | null;
}
@Component({
selector: 'app-move-history',
standalone: true,
imports: [],
templateUrl: './move-history.component.html',
styleUrl: './move-history.component.css'
})
export class MoveHistoryComponent implements OnChanges {
@Input({ required: true }) moves: string[] = [];
@Output() navigate = new EventEmitter<MoveNavDirection>();
movePairs: MovePair[] = [];
get plyCount(): number {
return this.moves.length;
}
get currentWhiteIndex(): number {
const lastPairIndex = this.movePairs.length - 1;
if (lastPairIndex < 0) return -1;
const lastMove = this.moves.length - 1;
return lastMove % 2 === 0 ? lastPairIndex : -1;
}
get currentBlackIndex(): number {
const lastPairIndex = this.movePairs.length - 1;
if (lastPairIndex < 0) return -1;
const lastMove = this.moves.length - 1;
return lastMove % 2 === 1 ? lastPairIndex : -1;
}
ngOnChanges(): void {
this.movePairs = this.buildPairs(this.moves);
}
private buildPairs(moves: string[]): MovePair[] {
const pairs: MovePair[] = [];
for (let i = 0; i < moves.length; i += 2) {
pairs.push({ white: moves[i], black: moves[i + 1] ?? null });
}
return pairs;
}
}