Add playing handicap, 6-digit login code, and game UX improvements
- Playing handicap: computed at game creation (WHS formula), stored on game_players alongside per-hole strokes allocation; displayed on game summary with HC card and / markers on scorecard (only when SI defined); live game shows +N per player card when SI exists, HC total otherwise; new game confirmation previews computed HC per player - Login: 6-digit code sent alongside magic link in every auth email; check_email page has auto-advancing digit inputs with paste support; new POST /auth/verify-code route handles code verification - Game view: Score/Card toggle fixed with position:fixed to always show above nav bar on mobile; swipe on score view changes holes, swipe on scorecard switches tabs; dirty tracking prevents saving unmodified holes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -49,32 +49,28 @@
|
||||
</div>
|
||||
|
||||
{# Playing handicaps #}
|
||||
{% if playing_handicaps %}
|
||||
{% if playing_handicaps and playing_handicaps.values() | select | list %}
|
||||
<div class="card" style="margin-top:0.75rem; padding:0.75rem 1rem;">
|
||||
<div style="font-size:0.8rem; color:var(--text-muted); font-weight:500; margin-bottom:0.5rem; text-transform:uppercase; letter-spacing:0.05em;">Playing Handicaps</div>
|
||||
{% for p in players %}
|
||||
{% set ph = playing_handicaps.get(p.id) %}
|
||||
{% if ph is not none %}
|
||||
<div style="display:flex; align-items:center; gap:0.6rem; padding:0.35rem 0; {% if not loop.last %}border-bottom:1px solid var(--border);{% endif %} font-size:0.9rem;">
|
||||
<span>
|
||||
{% if p.avatar and p.avatar.startswith('/') %}
|
||||
<img src="{{ p.avatar }}" style="width:1.3rem;height:1.3rem;border-radius:50%;object-fit:cover;vertical-align:middle;">
|
||||
{% else %}
|
||||
{{ p.avatar or '👤' }}
|
||||
{% endif %}
|
||||
{% else %}{{ p.avatar or '👤' }}{% endif %}
|
||||
</span>
|
||||
<span style="flex:1; font-weight:500;">{{ p.name }}</span>
|
||||
{% if p.handicap_snapshot is not none %}
|
||||
<span style="color:var(--text-muted);">HI {{ p.handicap_snapshot }}</span>
|
||||
{% endif %}
|
||||
{% set ph = playing_handicaps.get(p.id) %}
|
||||
{% if ph is not none %}
|
||||
<span style="font-weight:600; color:var(--accent); min-width:3rem; text-align:right;">HC {{ ph }}</span>
|
||||
{% else %}
|
||||
<span style="color:var(--text-muted); min-width:3rem; text-align:right;">HC —</span>
|
||||
{% endif %}
|
||||
{% if p.tee_name %}
|
||||
<span style="color:var(--text-muted); font-size:0.8rem; min-width:4rem; text-align:right;">{{ p.tee_name }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -121,26 +117,15 @@
|
||||
{% if strokes %}
|
||||
{% if par %}
|
||||
{% set diff = strokes - par %}
|
||||
{% if strokes == 1 %}
|
||||
<span class="score-hio">{{ strokes }}</span>
|
||||
{% elif diff <= -2 %}
|
||||
<span class="score-eagle">{{ strokes }}</span>
|
||||
{% elif diff == -1 %}
|
||||
<span class="score-birdie">{{ strokes }}</span>
|
||||
{% elif diff == 1 %}
|
||||
<span class="score-bogey">{{ strokes }}</span>
|
||||
{% elif diff >= 2 %}
|
||||
<span class="score-double-bogey">{{ strokes }}</span>
|
||||
{% else %}
|
||||
{{ strokes }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ strokes }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
—
|
||||
{% endif %}
|
||||
{% if sr > 0 %}<sup style="color:var(--accent); font-size:0.6em; line-height:0;">{{ '·' * sr }}</sup>{% endif %}
|
||||
{% if strokes == 1 %}<span class="score-hio">{{ strokes }}</span>
|
||||
{% elif diff <= -2 %}<span class="score-eagle">{{ strokes }}</span>
|
||||
{% elif diff == -1 %}<span class="score-birdie">{{ strokes }}</span>
|
||||
{% elif diff == 1 %}<span class="score-bogey">{{ strokes }}</span>
|
||||
{% elif diff >= 2 %}<span class="score-double-bogey">{{ strokes }}</span>
|
||||
{% else %}{{ strokes }}{% endif %}
|
||||
{% else %}{{ strokes }}{% endif %}
|
||||
{% else %}—{% endif %}
|
||||
{% if has_stroke_index and sr > 0 %}<sup style="color:var(--accent); font-size:0.6em; line-height:0;">{{ '/' * sr }}</sup>{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
@@ -159,12 +144,14 @@
|
||||
<td>{{ stroke_total.val or '—' }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% if playing_handicaps %}
|
||||
{% set any_hc = playing_handicaps and playing_handicaps.values() | select | list %}
|
||||
{% if any_hc %}
|
||||
<tr>
|
||||
<td style="color:var(--text-muted); font-size:0.8rem;">HC</td>
|
||||
{% if hole_pars %}<td></td>{% endif %}
|
||||
{% for p in players %}
|
||||
<td style="color:var(--text-muted); font-size:0.8rem;">{{ playing_handicaps.get(p.id, '—') if playing_handicaps.get(p.id) is not none else '—' }}</td>
|
||||
{% set ph = playing_handicaps.get(p.id) %}
|
||||
<td style="color:var(--text-muted); font-size:0.8rem;">{{ ph if ph is not none else '—' }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
@@ -254,7 +241,7 @@
|
||||
{% else %}<span{% if is_winner %} class="skin-winner"{% endif %}>{{ strokes }}</span>{% endif %}
|
||||
{% else %}<span{% if is_winner %} class="skin-winner"{% endif %}>{{ strokes }}</span>{% endif %}
|
||||
{% else %}—{% endif %}
|
||||
{% if sr > 0 %}<sup style="color:var(--accent); font-size:0.6em; line-height:0;">{{ '·' * sr }}</sup>{% endif %}
|
||||
{% if has_stroke_index and sr > 0 %}<sup style="color:var(--accent); font-size:0.6em; line-height:0;">{{ '/' * sr }}</sup>{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
<td class="score-cell">
|
||||
|
||||
Reference in New Issue
Block a user