More responsive drag and drop for card plays

This commit is contained in:
2026-06-09 19:45:56 -07:00
parent e312d8efc1
commit 41731459a7
2 changed files with 36 additions and 11 deletions

View File

@@ -541,17 +541,17 @@ def play_card_route(
if not ok:
return HTMLResponse(f"<p class='alert alert-danger'>{msg}</p>", status_code=400)
# Return a success notification box that HTMX will show, or just return 204 to let polling pick it up.
# Returning a message is nice! But returning 204 is clean. Let's return a brief HTML snippet.
# Return a success notification and HX-Trigger header to refresh the hand.
color_prefix = "🟩" if res["success"] else "🟥"
drew_text = f" (Drew card: {res['drew_card']})" if res["drew_card"] else ""
return HTMLResponse(
f"<div class='play-notification' style='position:fixed;bottom:20px;right:20px;background:#152238;border:1px solid #d4af37;padding:15px;border-radius:8px;z-index:1000;' onclick='this.remove()'>"
drew_attr = "true" if res["drew_card"] else "false"
html = (
f"<div class='play-notification' data-drew='{drew_attr}' style='position:fixed;bottom:20px;right:20px;background:#152238;border:1px solid #d4af37;padding:15px;border-radius:8px;z-index:1000;' onclick='this.remove()'>"
f"<p>{color_prefix} {res['details']}{drew_text}</p>"
f"<span style='font-size:0.8em;color:#aaa;'>Click to dismiss</span>"
f"</div>",
headers={"HX-Trigger": "hand-updated"}
f"</div>"
)
return HTMLResponse(html, headers={"HX-Trigger": "hand-changed"})
# 12. Pi-Rat plays a Joker to replace an obstacle
@app.post("/game/{game_id}/player/{player_id}/play-joker")
@@ -566,13 +566,13 @@ def play_joker_route(
if not ok:
return HTMLResponse(f"<p class='alert alert-danger'>{msg}</p>", status_code=400)
return HTMLResponse(
f"<div class='play-notification' style='position:fixed;bottom:20px;right:20px;background:#152238;border:1px solid #d4af37;padding:15px;border-radius:8px;z-index:1000;' onclick='this.remove()'>"
html = (
f"<div class='play-notification' data-drew='false' style='position:fixed;bottom:20px;right:20px;background:#152238;border:1px solid #d4af37;padding:15px;border-radius:8px;z-index:1000;' onclick='this.remove()'>"
f"<p>🃏 Play Joker: Discarded obstacle and drew a new replacement!</p>"
f"<span style='font-size:0.8em;color:#aaa;'>Click to dismiss</span>"
f"</div>",
headers={"HX-Trigger": "hand-updated"}
f"</div>"
)
return HTMLResponse(html, headers={"HX-Trigger": "hand-changed"})
# 13. Toggle Objective Completion Checklist
@app.post("/game/{game_id}/player/{player_id}/objective/toggle")

View File

@@ -341,9 +341,34 @@
? `/game/${gameId}/player/${playerId}/play-joker`
: `/game/${gameId}/player/${playerId}/play-card`;
// Find the dragged card element before the request
const draggedCard = document.querySelector(
`.card-large[data-card-code="${cardCode}"]`
);
htmx.ajax('POST', url, {
values: { obstacle_id: obstacleId, card_code: cardCode },
swap: 'none'
target: 'body',
swap: 'beforeend'
}).then(function() {
// Remove the card from the hand on success
if (draggedCard && draggedCard.parentNode) {
draggedCard.remove();
}
// Check if hand is now empty (and no card was drawn)
const handFlex = document.querySelector('.hand-flex');
if (handFlex && handFlex.children.length === 0) {
handFlex.innerHTML = '<p class="empty-text text-center">Your hand is empty! (You draw cards when playing cards that match the suit color of the obstacle.)</p>';
}
// Auto-dismiss the notification after 3 seconds
const notif = document.querySelector('.play-notification:last-of-type');
if (notif) {
setTimeout(function() { notif.remove(); }, 3000);
// If a card was drawn, refresh the full view to show it
if (notif.getAttribute('data-drew') === 'true') {
htmx.trigger(document.body, 'phase-changed');
}
}
});
}
}