209 lines
8.8 KiB
HTML
209 lines
8.8 KiB
HTML
<nav class="nc-nav">
|
|
|
|
<!-- Logo -->
|
|
<div class="nc-logo" (click)="goToHome()" role="button" tabindex="0">
|
|
<div class="nc-logo-mark">♞</div>
|
|
<span class="nc-logo-text">NowChess</span>
|
|
</div>
|
|
|
|
<!-- Center links — only when logged in -->
|
|
@if (currentUser) {
|
|
<div class="nc-links">
|
|
<button type="button" class="nc-link">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
|
|
<circle cx="12" cy="12" r="3" />
|
|
</svg>
|
|
Watch
|
|
</button>
|
|
<button type="button" class="nc-link" (click)="goToTournaments()">Tournaments</button>
|
|
<button type="button" class="nc-link" (click)="goToBots()">Bots</button>
|
|
</div>
|
|
}
|
|
|
|
<!-- Right cluster -->
|
|
<div class="nc-right">
|
|
|
|
@if (currentUser; as user) {
|
|
|
|
<!-- Notifications bell -->
|
|
<div class="nc-dropdown-wrap" data-dropdown="notif">
|
|
<button type="button" class="nc-bell" [class.is-open]="notifOpen" (click)="toggleNotif($event)"
|
|
aria-label="Notifications">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" />
|
|
<path d="M10.3 21a1.94 1.94 0 0 0 3.4 0" />
|
|
</svg>
|
|
@if (incomingChallenges.length > 0) {
|
|
<span class="nc-badge">{{ incomingChallenges.length }}</span>
|
|
}
|
|
</button>
|
|
|
|
@if (notifOpen) {
|
|
<div class="nc-popover nc-notif" (click)="$event.stopPropagation()">
|
|
<div class="nc-notif-header">
|
|
<span class="nc-notif-header-title">Challenges</span>
|
|
</div>
|
|
|
|
<div class="nc-notif-list">
|
|
@if (incomingChallenges.length === 0) {
|
|
<div class="nc-notif-empty">No pending challenges</div>
|
|
}
|
|
@for (challenge of incomingChallenges; track challenge.id) {
|
|
<div class="nc-notif-row is-unread">
|
|
<div class="nc-notif-icon">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="14.5" y1="17.5" x2="3" y2="6" />
|
|
<path d="M13 19l6 -6" /><path d="M16 16l4 4" />
|
|
<path d="M19 21l2 -2" /><path d="M15 5l4 4" />
|
|
<path d="M21 3l-3 1l-4 4" />
|
|
</svg>
|
|
</div>
|
|
<div class="nc-notif-body">
|
|
<div class="nc-notif-text">
|
|
<b>{{ challenge.challenger.name }}</b> challenged you to a
|
|
{{ getTimeControlDisplay(challenge) }} game.
|
|
</div>
|
|
<div class="nc-notif-meta">
|
|
{{ challenge.challenger.rating }} · {{ challenge.timeControl.type ?? 'Custom' }} · {{ getExpirationInfo(challenge) }}
|
|
</div>
|
|
<div class="nc-notif-actions">
|
|
<button type="button" class="nc-btn-accept"
|
|
[disabled]="acceptingId === challenge.id || !!decliningId"
|
|
(click)="acceptChallenge($event, challenge)">
|
|
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="20 6 9 17 4 12" />
|
|
</svg>
|
|
{{ acceptingId === challenge.id ? '...' : 'Accept' }}
|
|
</button>
|
|
<button type="button" class="nc-btn-decline"
|
|
[disabled]="!!acceptingId || decliningId === challenge.id"
|
|
(click)="declineChallenge($event, challenge)">
|
|
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />
|
|
</svg>
|
|
{{ decliningId === challenge.id ? '...' : 'Decline' }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<div class="nc-notif-footer">
|
|
<button type="button" class="nc-view-all" (click)="goToChallenges()">View all challenges</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<!-- Games quick-access -->
|
|
<button type="button" class="nc-games-btn" (click)="goToGames()">
|
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M14.5 17.5L3 6"/>
|
|
<path d="M13 19l6-6"/><path d="M16 16l4 4"/>
|
|
<path d="M19 21l2-2"/><path d="M15 5l4 4"/>
|
|
<path d="M21 3l-3 1-4 4"/>
|
|
</svg>
|
|
Games
|
|
</button>
|
|
|
|
<!-- Profile -->
|
|
<div class="nc-dropdown-wrap" data-dropdown="profile">
|
|
<button type="button" class="nc-profile" [class.is-open]="profileOpen" (click)="toggleProfile($event)">
|
|
<div class="nc-avatar nc-avatar-sm">{{ getInitial() }}</div>
|
|
<span class="nc-profile-name">{{ user.username }}</span>
|
|
<svg class="nc-chevron" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="6 9 12 15 18 9" />
|
|
</svg>
|
|
</button>
|
|
|
|
@if (profileOpen) {
|
|
<div class="nc-popover nc-menu" (click)="$event.stopPropagation()">
|
|
<div class="nc-menu-header">
|
|
<div class="nc-avatar nc-avatar-md">{{ getInitial() }}</div>
|
|
<div>
|
|
<div class="nc-menu-user-name">{{ user.username }}</div>
|
|
<div class="nc-menu-user-sub">{{ user.rating }} · @{{ user.username }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="nc-menu-group">
|
|
<button type="button" class="nc-menu-item" (click)="goToProfile()">
|
|
<span class="nc-menu-icon">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
|
|
<circle cx="12" cy="7" r="4" />
|
|
</svg>
|
|
</span>
|
|
<span class="nc-menu-label">My profile</span>
|
|
</button>
|
|
|
|
<button type="button" class="nc-menu-item" (click)="goToChallenges()">
|
|
<span class="nc-menu-icon">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="14.5" y1="17.5" x2="3" y2="6" />
|
|
<path d="M13 19l6 -6" /><path d="M16 16l4 4" />
|
|
<path d="M19 21l2 -2" /><path d="M15 5l4 4" />
|
|
<path d="M21 3l-3 1l-4 4" />
|
|
</svg>
|
|
</span>
|
|
<span class="nc-menu-label">Challenges</span>
|
|
</button>
|
|
|
|
<button type="button" class="nc-menu-item" (click)="toggleTheme($event)">
|
|
<span class="nc-menu-icon">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z" />
|
|
</svg>
|
|
</span>
|
|
<span class="nc-menu-label">{{ isDarkMode ? 'Light mode' : 'Dark mode' }}</span>
|
|
<span class="nc-toggle" [class.is-on]="isDarkMode"></span>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="nc-menu-group">
|
|
<button type="button" class="nc-menu-item danger" (click)="logout()">
|
|
<span class="nc-menu-icon">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
|
|
<polyline points="16 17 21 12 16 7" />
|
|
<line x1="21" y1="12" x2="9" y2="12" />
|
|
</svg>
|
|
</span>
|
|
<span class="nc-menu-label">Log out</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
} @else {
|
|
|
|
<!-- Logged-out auth buttons -->
|
|
<button type="button" class="nc-auth-btn" (click)="openLoginDialog()">Login</button>
|
|
<button type="button" class="nc-auth-btn nc-auth-btn--primary" (click)="openRegisterDialog()">Register</button>
|
|
|
|
}
|
|
</div>
|
|
</nav>
|
|
|
|
@if (showLoginDialog) {
|
|
<app-login-dialog (onClose)="closeLoginDialog()" (onSuccess)="onLoginSuccess()" />
|
|
}
|
|
|
|
@if (showRegisterDialog) {
|
|
<app-register-dialog (onClose)="closeRegisterDialog()" (onSuccess)="onRegisterSuccess()" />
|
|
}
|