generated from bisco/codex-bootstrap
feat: improve scouting dashboard and demo data
This commit is contained in:
@@ -4,55 +4,107 @@
|
||||
<p class="eyebrow">Private basketball scouting</p>
|
||||
<h1>HoopScout</h1>
|
||||
</div>
|
||||
<div class="status">
|
||||
<span>{{ resultCount }}</span>
|
||||
<small>matches</small>
|
||||
<div class="scoreboard" aria-label="Scouting summary">
|
||||
<div>
|
||||
<span>{{ resultCount }}</span>
|
||||
<small>matches</small>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ averagePoints }}</span>
|
||||
<small>avg PPG</small>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ averageEfficiency }}</span>
|
||||
<small>avg EFF</small>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="filters" aria-label="Player filters">
|
||||
<label>
|
||||
<label class="search-field">
|
||||
Search
|
||||
<input type="search" [(ngModel)]="filters.q" placeholder="Name, role, team, nationality">
|
||||
<input
|
||||
type="search"
|
||||
[(ngModel)]="filters.q"
|
||||
(ngModelChange)="onFilterChange()"
|
||||
placeholder="Name, role, team, nationality"
|
||||
>
|
||||
</label>
|
||||
<label>
|
||||
Position
|
||||
<select [(ngModel)]="filters.position">
|
||||
<option *ngFor="let position of positions" [value]="position">{{ position || 'Any' }}</option>
|
||||
<select [(ngModel)]="filters.position" (ngModelChange)="onFilterChange()">
|
||||
<option value="">Any</option>
|
||||
<option *ngFor="let position of positions" [value]="position">{{ position }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Role
|
||||
<input type="text" [(ngModel)]="filters.role" placeholder="3 and D, handler, rim runner">
|
||||
<input
|
||||
type="text"
|
||||
[(ngModel)]="filters.role"
|
||||
(ngModelChange)="onFilterChange()"
|
||||
placeholder="3 and D, handler, rim runner"
|
||||
>
|
||||
</label>
|
||||
<label>
|
||||
League
|
||||
<select [(ngModel)]="filters.league">
|
||||
<option *ngFor="let league of leagues" [value]="league">{{ league || 'Any' }}</option>
|
||||
<select [(ngModel)]="filters.league" (ngModelChange)="onFilterChange()">
|
||||
<option value="">Any</option>
|
||||
<option *ngFor="let league of leagues" [value]="league">{{ league }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Min PPG
|
||||
<input type="number" [(ngModel)]="filters.minPoints" min="0" step="0.1">
|
||||
<input type="number" [(ngModel)]="filters.minPoints" (ngModelChange)="onFilterChange()" min="0" step="0.1">
|
||||
</label>
|
||||
<label>
|
||||
Min APG
|
||||
<input type="number" [(ngModel)]="filters.minAssists" min="0" step="0.1">
|
||||
<input type="number" [(ngModel)]="filters.minAssists" (ngModelChange)="onFilterChange()" min="0" step="0.1">
|
||||
</label>
|
||||
<label>
|
||||
Min RPG
|
||||
<input type="number" [(ngModel)]="filters.minRebounds" min="0" step="0.1">
|
||||
<input type="number" [(ngModel)]="filters.minRebounds" (ngModelChange)="onFilterChange()" min="0" step="0.1">
|
||||
</label>
|
||||
<label>
|
||||
Min EFF
|
||||
<input type="number" [(ngModel)]="filters.minEfficiency" min="0" step="0.1">
|
||||
<input
|
||||
type="number"
|
||||
[(ngModel)]="filters.minEfficiency"
|
||||
(ngModelChange)="onFilterChange()"
|
||||
min="0"
|
||||
step="0.1"
|
||||
>
|
||||
</label>
|
||||
<div class="actions">
|
||||
<button type="button" class="primary" (click)="search()">Search</button>
|
||||
<button type="button" class="primary" (click)="search()">Refresh</button>
|
||||
<button type="button" class="secondary" (click)="clearFilters()">Reset</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="quickbar" aria-label="Quick filters">
|
||||
<div class="chip-group">
|
||||
<button
|
||||
*ngFor="let position of positions"
|
||||
type="button"
|
||||
[class.active]="filters.position === position"
|
||||
(click)="togglePosition(position)"
|
||||
>
|
||||
{{ position }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="chip-group league-chips">
|
||||
<button
|
||||
*ngFor="let league of leagues"
|
||||
type="button"
|
||||
[class.active]="filters.league === league"
|
||||
(click)="toggleLeague(league)"
|
||||
>
|
||||
{{ league }}
|
||||
</button>
|
||||
</div>
|
||||
<span class="filter-count">{{ activeFiltersCount }} active</span>
|
||||
</section>
|
||||
|
||||
<p *ngIf="errorMessage" class="alert">{{ errorMessage }}</p>
|
||||
|
||||
<section class="workspace" aria-label="Scouting workspace">
|
||||
@@ -64,10 +116,18 @@
|
||||
<th>Pos</th>
|
||||
<th>League</th>
|
||||
<th>Team</th>
|
||||
<th>PPG</th>
|
||||
<th>APG</th>
|
||||
<th>RPG</th>
|
||||
<th>EFF</th>
|
||||
<th>
|
||||
<button type="button" class="sort" [class.active]="activeSort === 'points_per_game'" (click)="sortBy('points_per_game')">PPG</button>
|
||||
</th>
|
||||
<th>
|
||||
<button type="button" class="sort" [class.active]="activeSort === 'assists_per_game'" (click)="sortBy('assists_per_game')">APG</button>
|
||||
</th>
|
||||
<th>
|
||||
<button type="button" class="sort" [class.active]="activeSort === 'rebounds_per_game'" (click)="sortBy('rebounds_per_game')">RPG</button>
|
||||
</th>
|
||||
<th>
|
||||
<button type="button" class="sort" [class.active]="activeSort === 'efficiency_rating'" (click)="sortBy('efficiency_rating')">EFF</button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -100,6 +160,11 @@
|
||||
<h2>{{ selectedPlayer.name }}</h2>
|
||||
<p class="role">{{ selectedPlayer.position }} · {{ selectedPlayer.role || 'Role pending' }}</p>
|
||||
</div>
|
||||
<div class="profile-strip">
|
||||
<span>{{ selectedPlayer.nationality || '-' }}</span>
|
||||
<span>{{ selectedPlayer.height_cm || '-' }} cm</span>
|
||||
<span>{{ selectedPlayer.weight_kg || '-' }} kg</span>
|
||||
</div>
|
||||
<dl class="bio-grid">
|
||||
<div>
|
||||
<dt>League</dt>
|
||||
@@ -123,6 +188,14 @@
|
||||
<span>PPG</span>
|
||||
<strong>{{ statValue(selectedPlayer, 'points_per_game') }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>APG</span>
|
||||
<strong>{{ statValue(selectedPlayer, 'assists_per_game') }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>RPG</span>
|
||||
<strong>{{ statValue(selectedPlayer, 'rebounds_per_game') }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>TS%</span>
|
||||
<strong>{{ statValue(selectedPlayer, 'true_shooting_percentage') }}</strong>
|
||||
|
||||
Reference in New Issue
Block a user