3a1da1482c
- FastAPI + SQLite + Alpine.js + HTMX PWA for Bingo Bango Bongo golf scoring - Passwordless magic link auth with email (aiosmtplib) and admin invite system - Real-time score entry via WebSocket with drag-and-drop player ordering - Course management with per-hole par and stroke index - Scorecard with golf score markers (birdie, eagle, bogey, etc.) - Two-step new game form with tee selection per player - Dashboard with stats, live games social stream, and recent game history - Game summary view (read-only scorecard with leaderboard) - User profile pages with win stats - PWA install support with generated PNG icons - Admin panel for users, courses, games, and invitations Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
65 lines
2.5 KiB
HTML
65 lines
2.5 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}Games – Admin – Skins & Pins{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="page">
|
||
<div class="page-header">
|
||
<h1>⚙️ Admin</h1>
|
||
</div>
|
||
|
||
<div class="admin-subnav">
|
||
<a href="/admin" class="admin-subnav-item">Users</a>
|
||
<a href="/admin/courses" class="admin-subnav-item">Courses</a>
|
||
<a href="/admin/games" class="admin-subnav-item active">Games</a>
|
||
</div>
|
||
|
||
{% if request.query_params.get('success') %}
|
||
<div class="alert alert-success">{{ request.query_params.get('success') }}</div>
|
||
{% endif %}
|
||
|
||
{% if games %}
|
||
<div class="card" style="padding:0; overflow:hidden;">
|
||
{% for g in games %}
|
||
{% set plist = players_by_game.get(g.id, []) %}
|
||
<div style="padding:0.85rem 1rem; border-bottom:1px solid var(--border); display:flex; align-items:center; gap:0.75rem; flex-wrap:wrap;">
|
||
|
||
<div style="flex:1; min-width:0;">
|
||
<div style="font-weight:500; color:var(--text);">
|
||
{{ g.course_name or 'Unknown course' }}
|
||
<span class="status-badge status-{{ g.status }}" style="margin-left:0.4rem;">{{ g.status }}</span>
|
||
</div>
|
||
<div style="font-size:0.8rem; color:var(--text-muted); margin-top:0.2rem;">
|
||
{{ g.holes_count }} holes · {{ g.created_at[:10] }} · by {{ g.creator_name }}
|
||
</div>
|
||
<div style="font-size:0.8rem; color:var(--text-muted); margin-top:0.15rem;">
|
||
{% for p in plist %}
|
||
{% if p.avatar and p.avatar.startswith('/') %}
|
||
<img src="{{ p.avatar }}" style="width:1rem;height:1rem;border-radius:50%;object-fit:cover;vertical-align:middle;">
|
||
{% else %}
|
||
{{ p.avatar or '👤' }}
|
||
{% endif %}
|
||
<a href="/users/{{ p.id }}" style="color:inherit; text-decoration:none;">{{ p.name }}</a>{% if not loop.last %}, {% endif %}
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
|
||
<div style="display:flex; gap:0.4rem; flex-shrink:0;">
|
||
<a href="/games/{{ g.id }}" class="btn-table-action">Edit scores</a>
|
||
<form method="post" action="/admin/games/{{ g.id }}/delete" style="display:inline;"
|
||
onsubmit="return confirm('Delete this game? All scores will be lost.')">
|
||
<button type="submit" class="btn-table-action danger">Delete</button>
|
||
</form>
|
||
</div>
|
||
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
{% else %}
|
||
<div class="empty-state">
|
||
<div class="empty-icon">⛳</div>
|
||
<p>No games yet.</p>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
{% endblock %}
|