Add Skins as a side game for Bingo Bango Bongo
Players can now opt into a Skins side game when creating a BBB round. The side game uses the same skins settings (carryover, net/gross, skin value, double back nine). The scorecard gains a third Skins tab during play and on the summary; the BBB leaderboard continues to rank by BBB points. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,10 +11,10 @@
|
||||
{# ── Header ── #}
|
||||
<div class="game-header">
|
||||
<div style="display:flex; align-items:center; gap:0.75rem;">
|
||||
<button @click="view === 'score' ? prevHole() : cardView = 'strokes'" class="icon-btn"
|
||||
<button @click="view === 'score' ? prevHole() : cardPrev()" class="icon-btn"
|
||||
:disabled="view === 'score' ? currentHole <= 1 : cardView === 'strokes'">‹</button>
|
||||
<div style="text-align:center; flex:1;">
|
||||
<div class="hole-label" x-text="view === 'score' ? 'Hole ' + currentHole + ' / {{ game.holes_count }}' : (cardView === 'strokes' ? 'Strokes' : (GAME_FORMAT === 'skins' ? 'Skins' : 'Points'))"></div>
|
||||
<div class="hole-label" x-text="view === 'score' ? 'Hole ' + currentHole + ' / {{ game.holes_count }}' : (cardView === 'strokes' ? 'Strokes' : cardView === 'points' ? 'Points' : 'Skins')"></div>
|
||||
<div style="font-size:0.72rem; color:var(--text-muted); margin-top:0.1rem;">
|
||||
<template x-if="view === 'score'">
|
||||
<span x-text="(HOLE_PARS[currentHole] ? 'Par ' + HOLE_PARS[currentHole] : '') + (HOLE_SIS[currentHole] ? ' · SI ' + HOLE_SIS[currentHole] : '')"></span>
|
||||
@@ -24,8 +24,8 @@
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<button @click="view === 'score' ? nextHole() : cardView = (GAME_FORMAT === 'skins' ? 'skins' : 'points')" class="icon-btn"
|
||||
:disabled="view === 'score' ? currentHole >= {{ game.holes_count }} : cardView !== 'strokes'">›</button>
|
||||
<button @click="view === 'score' ? nextHole() : cardNext()" class="icon-btn"
|
||||
:disabled="view === 'score' ? currentHole >= {{ game.holes_count }} : cardView === (GAME_FORMAT === 'skins' || SIDE_SKINS_ENABLED ? 'skins' : 'points')">›</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -281,6 +281,7 @@ const SKINS_CARRYOVER = {{ carryover | tojson }};
|
||||
const SKIN_VALUE = {{ skin_value | tojson }};
|
||||
const SKIN_DOUBLE_BACK9 = {{ skin_double_back9 | tojson }};
|
||||
const SKINS_NET = {{ skins_net | tojson }};
|
||||
const SIDE_SKINS_ENABLED = {{ side_skins_enabled | tojson }};
|
||||
const HOLE_PARS = {{ hole_pars | tojson }};
|
||||
const HOLE_SIS = {{ hole_stroke_indices | tojson }};
|
||||
const STROKES_PER_HOLE = {{ strokes_per_hole | tojson }};
|
||||
@@ -457,6 +458,22 @@ function gameApp() {
|
||||
prevHole() { if (this.currentHole > 1) { this.saveHole(this.currentHole); this.currentHole--; } },
|
||||
nextHole() { if (this.currentHole < GAME_HOLES) { this.saveHole(this.currentHole); this.currentHole++; } },
|
||||
|
||||
cardTabs() {
|
||||
if (GAME_FORMAT === 'skins') return ['strokes', 'skins'];
|
||||
if (SIDE_SKINS_ENABLED) return ['strokes', 'points', 'skins'];
|
||||
return ['strokes', 'points'];
|
||||
},
|
||||
cardNext() {
|
||||
const tabs = this.cardTabs();
|
||||
const idx = tabs.indexOf(this.cardView);
|
||||
if (idx < tabs.length - 1) this.cardView = tabs[idx + 1];
|
||||
},
|
||||
cardPrev() {
|
||||
const tabs = this.cardTabs();
|
||||
const idx = tabs.indexOf(this.cardView);
|
||||
if (idx > 0) this.cardView = tabs[idx - 1];
|
||||
},
|
||||
|
||||
fmt(v) {
|
||||
return Number.isInteger(v) || v % 1 === 0 ? v.toFixed(0) : v.toFixed(1);
|
||||
},
|
||||
@@ -548,8 +565,7 @@ function gameApp() {
|
||||
if (this.view === 'score') {
|
||||
if (dx < 0) this.nextHole(); else this.prevHole();
|
||||
} else {
|
||||
const secondary = GAME_FORMAT === 'skins' ? 'skins' : 'points';
|
||||
this.cardView = dx < 0 ? secondary : 'strokes';
|
||||
if (dx < 0) this.cardNext(); else this.cardPrev();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
skinValue: '',
|
||||
skinDoubleBackNine: false,
|
||||
skinsNet: false,
|
||||
sideSkinsEnabled: false,
|
||||
holesCount: '',
|
||||
selectedPlayers: ['{{ user.id }}'],
|
||||
selectedTees: {},
|
||||
@@ -80,6 +81,7 @@
|
||||
backFromConfirm() { this.step = this.hasTees() ? 2 : 1; },
|
||||
formatLabel() {
|
||||
if (this.format === 'skins') return 'Skins';
|
||||
if (this.sideSkinsEnabled) return 'Bingo Bango Bongo + Skins';
|
||||
return 'Bingo Bango Bongo';
|
||||
}
|
||||
}">
|
||||
@@ -106,11 +108,18 @@
|
||||
</label>
|
||||
<label class="radio-card" style="flex:1;">
|
||||
<input type="radio" name="format" value="skins"
|
||||
@change="format = $event.target.value">
|
||||
@change="format = $event.target.value; sideSkinsEnabled = false">
|
||||
<span>Skins</span>
|
||||
</label>
|
||||
</div>
|
||||
<div x-show="format === 'skins'" style="margin-top:0.75rem; display:flex; flex-direction:column; gap:0.5rem;">
|
||||
<div x-show="format === 'bingo_bango_bongo'" style="margin-top:0.5rem;">
|
||||
<label style="display:flex; align-items:center; gap:0.5rem; cursor:pointer;">
|
||||
<input type="checkbox" style="width:auto;"
|
||||
@change="sideSkinsEnabled = $event.target.checked">
|
||||
<span style="font-weight:400; color:var(--text-muted);">Add Skins as a side game</span>
|
||||
</label>
|
||||
</div>
|
||||
<div x-show="format === 'skins' || sideSkinsEnabled" style="margin-top:0.75rem; display:flex; flex-direction:column; gap:0.5rem;">
|
||||
<input type="hidden" name="skins_net" :value="skinsNet ? '1' : '0'">
|
||||
<div style="display:flex; gap:0.75rem;">
|
||||
<label class="radio-card" style="flex:1;">
|
||||
@@ -288,15 +297,19 @@
|
||||
<span class="confirm-label">Format</span>
|
||||
<span class="confirm-value" x-text="formatLabel()"></span>
|
||||
</div>
|
||||
<div class="confirm-row" x-show="format === 'skins'">
|
||||
<div class="confirm-row" x-show="format === 'bingo_bango_bongo' && sideSkinsEnabled">
|
||||
<span class="confirm-label">Side game</span>
|
||||
<span class="confirm-value">Skins</span>
|
||||
</div>
|
||||
<div class="confirm-row" x-show="format === 'skins' || sideSkinsEnabled">
|
||||
<span class="confirm-label">Scoring</span>
|
||||
<span class="confirm-value" x-text="skinsNet ? 'Net (handicap)' : 'Straight up'"></span>
|
||||
</div>
|
||||
<div class="confirm-row" x-show="format === 'skins'">
|
||||
<div class="confirm-row" x-show="format === 'skins' || sideSkinsEnabled">
|
||||
<span class="confirm-label">Carryover</span>
|
||||
<span class="confirm-value" x-text="carryoverEnabled ? 'Yes' : 'No'"></span>
|
||||
</div>
|
||||
<div class="confirm-row" x-show="format === 'skins' && skinValue">
|
||||
<div class="confirm-row" x-show="(format === 'skins' || sideSkinsEnabled) && skinValue">
|
||||
<span class="confirm-label">Skin value</span>
|
||||
<span class="confirm-value" x-text="skinValue + (skinDoubleBackNine ? ' · doubles on back 9' : '')"></span>
|
||||
</div>
|
||||
@@ -354,6 +367,7 @@
|
||||
<template x-for="pid in selectedPlayers" :key="pid">
|
||||
<input type="hidden" name="players" :value="pid">
|
||||
</template>
|
||||
<input type="hidden" name="side_skins_enabled" :value="sideSkinsEnabled ? '1' : '0'">
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -84,11 +84,12 @@
|
||||
{# Scorecard toggle #}
|
||||
<div class="scorecard-toggle" style="margin-top:1rem;">
|
||||
<button @click="view = 'strokes'" :class="{ active: view === 'strokes' }">Strokes</button>
|
||||
{% if game.format == 'skins' %}
|
||||
<button @click="view = 'skins'" :class="{ active: view === 'skins' }">Skins</button>
|
||||
{% else %}
|
||||
{% if game.format != 'skins' %}
|
||||
<button @click="view = 'points'" :class="{ active: view === 'points' }">Points</button>
|
||||
{% endif %}
|
||||
{% if game.format == 'skins' or side_skins_enabled %}
|
||||
<button @click="view = 'skins'" :class="{ active: view === 'skins' }">Skins</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Strokes scorecard #}
|
||||
@@ -204,7 +205,7 @@
|
||||
</table>
|
||||
|
||||
{# Skins scorecard #}
|
||||
{% if game.format == 'skins' %}
|
||||
{% if game.format == 'skins' or side_skins_enabled %}
|
||||
<table class="scorecard" x-show="view === 'skins'">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user