Add full SkinsPins application

- 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>
This commit is contained in:
Rolf
2026-03-20 10:16:46 +01:00
parent 4b31b98f89
commit 3a1da1482c
51 changed files with 4964 additions and 1 deletions
+56
View File
@@ -0,0 +1,56 @@
{% extends "base.html" %}
{% block title %}Courses Skins &amp; 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 active">Courses</a>
<a href="/admin/games" class="admin-subnav-item">Games</a>
</div>
{% if request.query_params.get('success') %}
<div class="alert alert-success">{{ request.query_params.get('success') }}</div>
{% endif %}
<div style="display:flex; justify-content:flex-end; margin-bottom:1rem;">
<a href="/admin/courses/new" class="btn btn-primary" style="width:auto; padding:0.5rem 1rem;">+ New course</a>
</div>
{% if courses %}
<div class="card" style="padding:0;">
<table class="data-table" style="margin:0;">
<thead>
<tr><th>Course</th><th>Holes</th><th>Location</th><th></th></tr>
</thead>
<tbody>
{% for c in courses %}
<tr>
<td style="font-weight:500;">{{ c.name }}</td>
<td style="color:var(--text-muted);">{{ c.holes }}</td>
<td style="color:var(--text-muted);">{{ c.location or '—' }}</td>
<td style="white-space:nowrap;">
<a href="/admin/courses/{{ c.id }}/edit" class="btn-table-action">Edit</a>
<form method="post" action="/admin/courses/{{ c.id }}/delete" style="display:inline;"
onsubmit="return confirm('Delete {{ c.name }}? This cannot be undone.')">
<button type="submit" class="btn-table-action danger">Delete</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="empty-state">
<div class="empty-icon"></div>
<p>No courses yet.</p>
<a href="/admin/courses/new" class="btn btn-primary" style="margin-top:1rem; max-width:200px;">Add a course</a>
</div>
{% endif %}
</div>
{% endblock %}